spark 2.1.0 splat viewer tab with OS-fused gyro look-around
WebView-hosted Spark renderer (butterfly.spz demo scene), fixed camera position, rotation driven by expo-sensors DeviceMotion (ROTATION_VECTOR / CoreMotion xMagneticNorthZVertical) via injectJavaScript; web fallback uses deviceorientation in an iframe. Tap to re-center yaw.
This commit is contained in:
@@ -27,6 +27,12 @@
|
|||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"expo-router",
|
"expo-router",
|
||||||
|
[
|
||||||
|
"expo-sensors",
|
||||||
|
{
|
||||||
|
"motionPermission": "Allow $(PRODUCT_NAME) to use device motion to rotate the 3D view."
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"expo-splash-screen",
|
"expo-splash-screen",
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,6 +23,13 @@ export default function TabLayout() {
|
|||||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
|
tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="splat"
|
||||||
|
options={{
|
||||||
|
title: 'Splat',
|
||||||
|
tabBarIcon: ({ color }) => <IconSymbol size={28} name="rotate.3d" color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="explore"
|
name="explore"
|
||||||
options={{
|
options={{
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { SplatViewer } from '@/components/splat-viewer';
|
||||||
|
|
||||||
|
export default function SplatScreen() {
|
||||||
|
return <SplatViewer />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { DeviceMotion } from 'expo-sensors';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
|
||||||
|
|
||||||
|
import { rotationScript, SPLAT_VIEWER_HTML, type ViewerMessage } from './viewer-html';
|
||||||
|
|
||||||
|
const SENSOR_UPDATE_INTERVAL_MS = 1000 / 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native (iOS/Android) splat viewer host.
|
||||||
|
*
|
||||||
|
* Renders the Spark viewer page in a WebView and streams the OS's fused
|
||||||
|
* device attitude (expo-sensors `DeviceMotion.rotation`: ROTATION_VECTOR on
|
||||||
|
* Android, CoreMotion attitude on iOS — gyro+accel+mag on both) into the
|
||||||
|
* page via `injectJavaScript`. Camera position stays fixed; only rotation
|
||||||
|
* is live.
|
||||||
|
*/
|
||||||
|
export function SplatViewer() {
|
||||||
|
const webViewRef = useRef<WebView>(null);
|
||||||
|
const [status, setStatus] = useState('Loading Spark renderer…');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let subscription: { remove(): void } | undefined;
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const available = await DeviceMotion.isAvailableAsync();
|
||||||
|
if (cancelled) return;
|
||||||
|
if (!available) {
|
||||||
|
setStatus('Motion sensors unavailable — showing a static view.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DeviceMotion.setUpdateInterval(SENSOR_UPDATE_INTERVAL_MS);
|
||||||
|
subscription = DeviceMotion.addListener(({ rotation, orientation }) => {
|
||||||
|
if (!rotation) return;
|
||||||
|
const script = rotationScript({
|
||||||
|
alpha: rotation.alpha,
|
||||||
|
beta: rotation.beta,
|
||||||
|
gamma: rotation.gamma,
|
||||||
|
orientation: orientation ?? 0,
|
||||||
|
});
|
||||||
|
if (script) webViewRef.current?.injectJavaScript(script);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
subscription?.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onMessage = (event: WebViewMessageEvent) => {
|
||||||
|
let message: ViewerMessage;
|
||||||
|
try {
|
||||||
|
message = JSON.parse(event.nativeEvent.data);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (message.type) {
|
||||||
|
case 'progress':
|
||||||
|
setStatus(`Downloading scene… ${Math.round((100 * message.loaded) / message.total)}%`);
|
||||||
|
break;
|
||||||
|
case 'ready':
|
||||||
|
setStatus(`${message.numSplats.toLocaleString()} splats — move the phone to look around, tap to re-center.`);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
setStatus(`Viewer error: ${message.message}`);
|
||||||
|
break;
|
||||||
|
case 'stats':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<WebView
|
||||||
|
ref={webViewRef}
|
||||||
|
source={{ html: SPLAT_VIEWER_HTML }}
|
||||||
|
originWhitelist={['*']}
|
||||||
|
onMessage={onMessage}
|
||||||
|
scrollEnabled={false}
|
||||||
|
bounces={false}
|
||||||
|
overScrollMode="never"
|
||||||
|
setBuiltInZoomControls={false}
|
||||||
|
webviewDebuggingEnabled={__DEV__}
|
||||||
|
style={styles.webview}
|
||||||
|
/>
|
||||||
|
<Text style={styles.status}>{status}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#000',
|
||||||
|
},
|
||||||
|
webview: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#000',
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 12,
|
||||||
|
left: 12,
|
||||||
|
right: 12,
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: 'center',
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
||||||
|
borderRadius: 8,
|
||||||
|
paddingVertical: 6,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import { SPLAT_VIEWER_HTML, type ViewerMessage } from './viewer-html';
|
||||||
|
|
||||||
|
// expo-sensors' DeviceMotion web shim does not emit `rotation`, so on web we
|
||||||
|
// read the browser's own OS-fused attitude directly. Chrome/Android exposes
|
||||||
|
// the magnetometer-referenced fusion on `deviceorientationabsolute`; other
|
||||||
|
// browsers (incl. iOS Safari, which fuses via CoreMotion) use
|
||||||
|
// `deviceorientation`.
|
||||||
|
const ORIENTATION_EVENT =
|
||||||
|
typeof window !== 'undefined' && 'ondeviceorientationabsolute' in window
|
||||||
|
? 'deviceorientationabsolute'
|
||||||
|
: 'deviceorientation';
|
||||||
|
|
||||||
|
// iOS Safari 13+ gates motion events behind a user-gesture permission prompt.
|
||||||
|
const orientationEventStatics =
|
||||||
|
typeof DeviceOrientationEvent !== 'undefined'
|
||||||
|
? (DeviceOrientationEvent as unknown as { requestPermission?: () => Promise<'granted' | 'denied'> })
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const DEG2RAD = Math.PI / 180;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web splat viewer host: same Spark viewer page as native, hosted in an
|
||||||
|
* iframe and fed rotation samples via postMessage. Camera position is fixed.
|
||||||
|
*/
|
||||||
|
export function SplatViewer() {
|
||||||
|
const frameRef = useRef<HTMLIFrameElement>(null);
|
||||||
|
const [status, setStatus] = useState('Loading Spark renderer…');
|
||||||
|
const [needsPermission, setNeedsPermission] = useState(false);
|
||||||
|
|
||||||
|
const onOrientation = useCallback((event: DeviceOrientationEvent) => {
|
||||||
|
if (event.alpha == null || event.beta == null || event.gamma == null) return;
|
||||||
|
frameRef.current?.contentWindow?.postMessage(
|
||||||
|
{
|
||||||
|
type: 'rotation',
|
||||||
|
alpha: event.alpha * DEG2RAD,
|
||||||
|
beta: event.beta * DEG2RAD,
|
||||||
|
gamma: event.gamma * DEG2RAD,
|
||||||
|
orientation: (typeof screen !== 'undefined' && screen.orientation?.angle) || 0,
|
||||||
|
},
|
||||||
|
'*',
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onViewerMessage = (event: MessageEvent) => {
|
||||||
|
if (event.source !== frameRef.current?.contentWindow) return;
|
||||||
|
const message = event.data as ViewerMessage;
|
||||||
|
switch (message?.type) {
|
||||||
|
case 'progress':
|
||||||
|
setStatus(`Downloading scene… ${Math.round((100 * message.loaded) / message.total)}%`);
|
||||||
|
break;
|
||||||
|
case 'ready':
|
||||||
|
setStatus(`${message.numSplats.toLocaleString()} splats — rotate the device to look around, tap to re-center.`);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
setStatus(`Viewer error: ${message.message}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('message', onViewerMessage);
|
||||||
|
|
||||||
|
const listener = onOrientation as EventListener;
|
||||||
|
if (typeof orientationEventStatics.requestPermission === 'function') {
|
||||||
|
setNeedsPermission(true);
|
||||||
|
} else {
|
||||||
|
window.addEventListener(ORIENTATION_EVENT, listener);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('message', onViewerMessage);
|
||||||
|
window.removeEventListener(ORIENTATION_EVENT, listener);
|
||||||
|
};
|
||||||
|
}, [onOrientation]);
|
||||||
|
|
||||||
|
const requestMotionAccess = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const response = await orientationEventStatics.requestPermission?.();
|
||||||
|
if (response === 'granted') {
|
||||||
|
window.addEventListener(ORIENTATION_EVENT, onOrientation as EventListener);
|
||||||
|
setNeedsPermission(false);
|
||||||
|
} else {
|
||||||
|
setStatus('Motion access denied — showing a static view.');
|
||||||
|
setNeedsPermission(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setStatus(`Motion permission failed: ${error instanceof Error ? error.message : error}`);
|
||||||
|
}
|
||||||
|
}, [onOrientation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<iframe
|
||||||
|
ref={frameRef}
|
||||||
|
title="Spark splat viewer"
|
||||||
|
srcDoc={SPLAT_VIEWER_HTML}
|
||||||
|
style={iframeStyle}
|
||||||
|
allow="accelerometer; gyroscope; magnetometer"
|
||||||
|
/>
|
||||||
|
{needsPermission && (
|
||||||
|
<Pressable style={styles.permissionButton} onPress={requestMotionAccess}>
|
||||||
|
<Text style={styles.permissionLabel}>Enable motion control</Text>
|
||||||
|
</Pressable>
|
||||||
|
)}
|
||||||
|
<Text style={styles.status}>{status}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const iframeStyle: React.CSSProperties = {
|
||||||
|
position: 'absolute',
|
||||||
|
inset: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
border: 0,
|
||||||
|
background: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#000',
|
||||||
|
},
|
||||||
|
permissionButton: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: '45%',
|
||||||
|
alignSelf: 'center',
|
||||||
|
backgroundColor: 'rgba(10, 126, 164, 0.9)',
|
||||||
|
borderRadius: 10,
|
||||||
|
paddingVertical: 12,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
},
|
||||||
|
permissionLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 12,
|
||||||
|
left: 12,
|
||||||
|
right: 12,
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: 'center',
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
||||||
|
borderRadius: 8,
|
||||||
|
paddingVertical: 6,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/**
|
||||||
|
* Self-contained Spark (sparkjs.dev) Gaussian-splat viewer page.
|
||||||
|
*
|
||||||
|
* Hosted inside `react-native-webview` on iOS/Android and inside an <iframe>
|
||||||
|
* on web, per the WebView-renderer architecture in prototyping-session.md.
|
||||||
|
* The page renders a fixed-position camera whose *rotation* is driven by the
|
||||||
|
* host through a single message contract:
|
||||||
|
*
|
||||||
|
* - native host: `webViewRef.injectJavaScript(rotationScript(sample))`
|
||||||
|
* - web host: `iframe.contentWindow.postMessage({ type: 'rotation', ...sample }, '*')`
|
||||||
|
*
|
||||||
|
* A rotation sample is the W3C device-orientation triple (alpha/beta/gamma,
|
||||||
|
* intrinsic Z-X'-Y'', in RADIANS) plus the screen-orientation angle in
|
||||||
|
* degrees (0 | 90 | 180 | -90). Both expo-sensors `DeviceMotion.rotation`
|
||||||
|
* (Android ROTATION_VECTOR, iOS CoreMotion attitude — the OS's fused
|
||||||
|
* gyro+accel+mag estimate on both) and the browser's `deviceorientation`
|
||||||
|
* event (degrees, converted by the web host) decompose the same way, so one
|
||||||
|
* reconstruction works for every source.
|
||||||
|
*
|
||||||
|
* The page reports back `{ type: 'ready' | 'error' | 'stats', ... }` via
|
||||||
|
* `window.ReactNativeWebView.postMessage` (native) or `parent.postMessage`
|
||||||
|
* (web).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Spark's flagship publicly hosted demo scene (~4 MB .spz). */
|
||||||
|
export const SPLAT_SCENE_URL = 'https://sparkjs.dev/assets/splats/butterfly.spz';
|
||||||
|
|
||||||
|
/** Latest Spark release (2.1.0) and its pinned three.js peer. */
|
||||||
|
const SPARK_MODULE_URL = 'https://cdn.jsdelivr.net/npm/@sparkjsdev/spark@2.1.0/dist/spark.module.js';
|
||||||
|
const THREE_MODULE_URL = 'https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js';
|
||||||
|
const THREE_ADDONS_URL = 'https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/';
|
||||||
|
|
||||||
|
export interface RotationSample {
|
||||||
|
/** Rotation around Z, radians (W3C convention). */
|
||||||
|
alpha: number;
|
||||||
|
/** Rotation around X, radians. */
|
||||||
|
beta: number;
|
||||||
|
/** Rotation around Y, radians. */
|
||||||
|
gamma: number;
|
||||||
|
/** Screen orientation angle in degrees: 0, 90, 180 or -90. */
|
||||||
|
orientation: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Message posted by the viewer page to its host. */
|
||||||
|
export type ViewerMessage =
|
||||||
|
| { type: 'ready'; numSplats: number }
|
||||||
|
| { type: 'progress'; loaded: number; total: number }
|
||||||
|
| { type: 'stats'; fps: number }
|
||||||
|
| { type: 'error'; message: string };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JS snippet for `WebView.injectJavaScript` pushing one rotation sample.
|
||||||
|
* Values are interpolated as plain number literals; non-finite samples are
|
||||||
|
* dropped so we never inject `NaN`/`undefined` into the page.
|
||||||
|
*/
|
||||||
|
export function rotationScript({ alpha, beta, gamma, orientation }: RotationSample): string | null {
|
||||||
|
if (!Number.isFinite(alpha) || !Number.isFinite(beta) || !Number.isFinite(gamma)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return `window.__setRotation&&window.__setRotation(${alpha},${beta},${gamma},${orientation || 0});true;`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SPLAT_VIEWER_HTML = /* html */ `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0; height: 100%; overflow: hidden; background: #000; }
|
||||||
|
canvas { display: block; }
|
||||||
|
#hud {
|
||||||
|
position: fixed; top: max(8px, env(safe-area-inset-top)); left: 8px;
|
||||||
|
color: #8f8; font: 11px/1.5 ui-monospace, monospace;
|
||||||
|
background: rgba(0, 0, 0, 0.45); padding: 4px 7px; border-radius: 4px;
|
||||||
|
pointer-events: none; white-space: pre; z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"three": "${THREE_MODULE_URL}",
|
||||||
|
"three/addons/": "${THREE_ADDONS_URL}",
|
||||||
|
"@sparkjsdev/spark": "${SPARK_MODULE_URL}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="hud">loading spark 2.1.0…</div>
|
||||||
|
<script>
|
||||||
|
// Host bridge + error funnel. Plain script so it runs even if the module
|
||||||
|
// graph below fails to fetch/parse.
|
||||||
|
(function () {
|
||||||
|
window.__emit = function (msg) {
|
||||||
|
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
||||||
|
window.ReactNativeWebView.postMessage(JSON.stringify(msg));
|
||||||
|
} else if (window.parent !== window) {
|
||||||
|
window.parent.postMessage(msg, '*');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('error', function (e) {
|
||||||
|
window.__emit({ type: 'error', message: String((e.error && e.error.message) || e.message) });
|
||||||
|
});
|
||||||
|
window.addEventListener('unhandledrejection', function (e) {
|
||||||
|
window.__emit({ type: 'error', message: String((e.reason && e.reason.message) || e.reason) });
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<script type="module">
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { SparkRenderer, SplatMesh } from '@sparkjsdev/spark';
|
||||||
|
|
||||||
|
const SPLAT_URL = '${SPLAT_SCENE_URL}';
|
||||||
|
const hud = document.getElementById('hud');
|
||||||
|
const emit = window.__emit;
|
||||||
|
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.01, 1000);
|
||||||
|
const renderer = new THREE.WebGLRenderer({ antialias: false, powerPreference: 'high-performance' });
|
||||||
|
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
|
||||||
|
renderer.setSize(innerWidth, innerHeight);
|
||||||
|
document.body.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
const spark = new SparkRenderer({ renderer });
|
||||||
|
scene.add(spark);
|
||||||
|
|
||||||
|
// Camera position is FIXED (origin); only orientation is live. The splat is
|
||||||
|
// placed in front of the initial view, flipped 180° about X because 3DGS
|
||||||
|
// captures are Y-down (as in Spark's own hello-world).
|
||||||
|
const splat = new SplatMesh({
|
||||||
|
url: SPLAT_URL,
|
||||||
|
onProgress: (e) => {
|
||||||
|
if (e.lengthComputable) {
|
||||||
|
hud.textContent = 'downloading scene… ' + Math.round((100 * e.loaded) / e.total) + '%';
|
||||||
|
emit({ type: 'progress', loaded: e.loaded, total: e.total });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
splat.quaternion.set(1, 0, 0, 0);
|
||||||
|
splat.position.set(0, 0, -2.7);
|
||||||
|
scene.add(splat);
|
||||||
|
|
||||||
|
let numSplats = 0;
|
||||||
|
splat.initialized
|
||||||
|
.then((mesh) => {
|
||||||
|
numSplats = mesh.numSplats;
|
||||||
|
emit({ type: 'ready', numSplats });
|
||||||
|
})
|
||||||
|
.catch((err) => emit({ type: 'error', message: 'splat load failed: ' + (err && err.message ? err.message : err) }));
|
||||||
|
|
||||||
|
// ---- Device attitude -> camera quaternion --------------------------------
|
||||||
|
// Standard W3C mapping (as in three.js DeviceOrientationControls):
|
||||||
|
// world is Y-up, the camera looks out of the BACK of the device.
|
||||||
|
const euler = new THREE.Euler();
|
||||||
|
const qTmp = new THREE.Quaternion();
|
||||||
|
const deviceQ = new THREE.Quaternion();
|
||||||
|
const yawFix = new THREE.Quaternion();
|
||||||
|
const forward = new THREE.Vector3();
|
||||||
|
const Y_AXIS = new THREE.Vector3(0, 1, 0);
|
||||||
|
const Z_AXIS = new THREE.Vector3(0, 0, 1);
|
||||||
|
const Q_CAMERA = new THREE.Quaternion(-Math.SQRT1_2, 0, 0, Math.SQRT1_2); // -90° about X
|
||||||
|
const DEG2RAD = Math.PI / 180;
|
||||||
|
|
||||||
|
let hasPose = false;
|
||||||
|
let needRecenter = true;
|
||||||
|
|
||||||
|
// alpha/beta/gamma in radians, screenDeg in degrees.
|
||||||
|
function setRotation(alpha, beta, gamma, screenDeg) {
|
||||||
|
if (!Number.isFinite(alpha) || !Number.isFinite(beta) || !Number.isFinite(gamma)) return;
|
||||||
|
euler.set(beta, alpha, -gamma, 'YXZ');
|
||||||
|
deviceQ.setFromEuler(euler);
|
||||||
|
deviceQ.multiply(Q_CAMERA);
|
||||||
|
deviceQ.multiply(qTmp.setFromAxisAngle(Z_AXIS, -(screenDeg || 0) * DEG2RAD));
|
||||||
|
|
||||||
|
if (needRecenter) {
|
||||||
|
// Attitude yaw is referenced to magnetic north (OS fusion); re-zero it
|
||||||
|
// so the first sample looks straight at the scene. Pitch/roll stay
|
||||||
|
// gravity-true. Skipped while the camera points near straight up/down,
|
||||||
|
// where heading is ill-defined.
|
||||||
|
forward.set(0, 0, -1).applyQuaternion(deviceQ);
|
||||||
|
if (forward.x * forward.x + forward.z * forward.z > 0.01) {
|
||||||
|
yawFix.setFromAxisAngle(Y_AXIS, Math.atan2(forward.x, -forward.z));
|
||||||
|
needRecenter = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
camera.quaternion.copy(yawFix).multiply(deviceQ);
|
||||||
|
hasPose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native host entry point (WebView.injectJavaScript).
|
||||||
|
window.__setRotation = setRotation;
|
||||||
|
// Web host entry point (iframe postMessage).
|
||||||
|
window.addEventListener('message', (e) => {
|
||||||
|
const d = e.data;
|
||||||
|
if (d && d.type === 'rotation') setRotation(d.alpha, d.beta, d.gamma, d.orientation);
|
||||||
|
});
|
||||||
|
// Tap anywhere to re-center the view on the scene.
|
||||||
|
window.addEventListener('pointerdown', () => { needRecenter = true; });
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
camera.aspect = innerWidth / innerHeight;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
renderer.setSize(innerWidth, innerHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ---- Render loop + HUD ---------------------------------------------------
|
||||||
|
let frames = 0;
|
||||||
|
let lastHud = performance.now();
|
||||||
|
renderer.setAnimationLoop(() => {
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
frames += 1;
|
||||||
|
const now = performance.now();
|
||||||
|
if (now - lastHud >= 1000) {
|
||||||
|
if (numSplats > 0) {
|
||||||
|
hud.textContent =
|
||||||
|
numSplats.toLocaleString() + ' splats | ' + frames + ' fps | ' +
|
||||||
|
(hasPose ? 'gyro live — tap to re-center' : 'waiting for gyro…');
|
||||||
|
}
|
||||||
|
emit({ type: 'stats', fps: frames });
|
||||||
|
frames = 0;
|
||||||
|
lastHud = now;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
@@ -18,6 +18,7 @@ const MAPPING = {
|
|||||||
'paperplane.fill': 'send',
|
'paperplane.fill': 'send',
|
||||||
'chevron.left.forwardslash.chevron.right': 'code',
|
'chevron.left.forwardslash.chevron.right': 'code',
|
||||||
'chevron.right': 'chevron-right',
|
'chevron.right': 'chevron-right',
|
||||||
|
'rotate.3d': 'view-in-ar',
|
||||||
} as IconMapping;
|
} as IconMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+6
-4
@@ -22,6 +22,7 @@
|
|||||||
"expo-image": "~3.0.11",
|
"expo-image": "~3.0.11",
|
||||||
"expo-linking": "~8.0.12",
|
"expo-linking": "~8.0.12",
|
||||||
"expo-router": "~6.0.24",
|
"expo-router": "~6.0.24",
|
||||||
|
"expo-sensors": "~15.0.8",
|
||||||
"expo-splash-screen": "~31.0.13",
|
"expo-splash-screen": "~31.0.13",
|
||||||
"expo-status-bar": "~3.0.9",
|
"expo-status-bar": "~3.0.9",
|
||||||
"expo-symbols": "~1.0.8",
|
"expo-symbols": "~1.0.8",
|
||||||
@@ -31,17 +32,18 @@
|
|||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.81.5",
|
"react-native": "0.81.5",
|
||||||
"react-native-gesture-handler": "~2.28.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-worklets": "0.5.1",
|
|
||||||
"react-native-reanimated": "~4.1.1",
|
"react-native-reanimated": "~4.1.1",
|
||||||
"react-native-safe-area-context": "~5.6.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
"react-native-screens": "~4.16.0",
|
"react-native-screens": "~4.16.0",
|
||||||
"react-native-web": "~0.21.0"
|
"react-native-web": "~0.21.0",
|
||||||
|
"react-native-webview": "13.15.0",
|
||||||
|
"react-native-worklets": "0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "~19.1.0",
|
"@types/react": "~19.1.0",
|
||||||
"typescript": "~5.9.2",
|
|
||||||
"eslint": "^9.25.0",
|
"eslint": "^9.25.0",
|
||||||
"eslint-config-expo": "~10.0.0"
|
"eslint-config-expo": "~10.0.0",
|
||||||
|
"typescript": "~5.9.2"
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+59
-27
@@ -22,7 +22,7 @@ importers:
|
|||||||
version: 7.3.16(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 7.3.16(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
expo:
|
expo:
|
||||||
specifier: ~54.0.35
|
specifier: ~54.0.35
|
||||||
version: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
version: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
expo-constants:
|
expo-constants:
|
||||||
specifier: ~18.0.13
|
specifier: ~18.0.13
|
||||||
version: 18.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
version: 18.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
||||||
@@ -41,6 +41,9 @@ importers:
|
|||||||
expo-router:
|
expo-router:
|
||||||
specifier: ~6.0.24
|
specifier: ~6.0.24
|
||||||
version: 6.0.24(@expo/metro-runtime@6.1.2)(@types/react@19.1.17)(expo-constants@18.0.13)(expo-linking@8.0.12)(expo@54.0.36)(react-dom@19.1.0(react@19.1.0))(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.7(react-native-worklets@0.5.1(@babel/core@7.29.7)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 6.0.24(@expo/metro-runtime@6.1.2)(@types/react@19.1.17)(expo-constants@18.0.13)(expo-linking@8.0.12)(expo@54.0.36)(react-dom@19.1.0(react@19.1.0))(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.7(react-native-worklets@0.5.1(@babel/core@7.29.7)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
|
expo-sensors:
|
||||||
|
specifier: ~15.0.8
|
||||||
|
version: 15.0.8(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
||||||
expo-splash-screen:
|
expo-splash-screen:
|
||||||
specifier: ~31.0.13
|
specifier: ~31.0.13
|
||||||
version: 31.0.13(expo@54.0.36)(typescript@5.9.3)
|
version: 31.0.13(expo@54.0.36)(typescript@5.9.3)
|
||||||
@@ -80,6 +83,9 @@ importers:
|
|||||||
react-native-web:
|
react-native-web:
|
||||||
specifier: ~0.21.0
|
specifier: ~0.21.0
|
||||||
version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
react-native-webview:
|
||||||
|
specifier: 13.15.0
|
||||||
|
version: 13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
react-native-worklets:
|
react-native-worklets:
|
||||||
specifier: 0.5.1
|
specifier: 0.5.1
|
||||||
version: 0.5.1(@babel/core@7.29.7)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 0.5.1(@babel/core@7.29.7)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
@@ -2290,6 +2296,12 @@ packages:
|
|||||||
react-server-dom-webpack:
|
react-server-dom-webpack:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
expo-sensors@15.0.8:
|
||||||
|
resolution: {integrity: sha512-ttibOSCYjFAMIfjV+vVukO1v7GKlbcPRfxcRqbTaSMGneewDwVSXbGFImY530fj1BR3mWq4n9jHnuDp8tAEY9g==}
|
||||||
|
peerDependencies:
|
||||||
|
expo: '*'
|
||||||
|
react-native: '*'
|
||||||
|
|
||||||
expo-server@1.0.7:
|
expo-server@1.0.7:
|
||||||
resolution: {integrity: sha512-mcmyML3oXcqFUXUxtdtCL1O00ztNI2v76d+MdniXRUgHNxIcHZ05zo+DqBaOOT6LQnPk4vA4YHqQl7iGUfRb3g==}
|
resolution: {integrity: sha512-mcmyML3oXcqFUXUxtdtCL1O00ztNI2v76d+MdniXRUgHNxIcHZ05zo+DqBaOOT6LQnPk4vA4YHqQl7iGUfRb3g==}
|
||||||
engines: {node: '>=20.16.0'}
|
engines: {node: '>=20.16.0'}
|
||||||
@@ -3523,6 +3535,12 @@ packages:
|
|||||||
react: ^18.0.0 || ^19.0.0
|
react: ^18.0.0 || ^19.0.0
|
||||||
react-dom: ^18.0.0 || ^19.0.0
|
react-dom: ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
react-native-webview@13.15.0:
|
||||||
|
resolution: {integrity: sha512-Vzjgy8mmxa/JO6l5KZrsTC7YemSdq+qB01diA0FqjUTaWGAGwuykpJ73MDj3+mzBSlaDxAEugHzTtkUQkQEQeQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '*'
|
||||||
|
react-native: '*'
|
||||||
|
|
||||||
react-native-worklets@0.5.1:
|
react-native-worklets@0.5.1:
|
||||||
resolution: {integrity: sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==}
|
resolution: {integrity: sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -4982,7 +5000,7 @@ snapshots:
|
|||||||
connect: 3.7.0
|
connect: 3.7.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
env-editor: 0.4.2
|
env-editor: 0.4.2
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
expo-server: 1.0.7
|
expo-server: 1.0.7
|
||||||
freeport-async: 2.0.0
|
freeport-async: 2.0.0
|
||||||
getenv: 2.0.0
|
getenv: 2.0.0
|
||||||
@@ -5159,7 +5177,7 @@ snapshots:
|
|||||||
postcss: 8.4.49
|
postcss: 8.4.49
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -5168,7 +5186,7 @@ snapshots:
|
|||||||
'@expo/metro-runtime@6.1.2(expo@54.0.36)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
|
'@expo/metro-runtime@6.1.2(expo@54.0.36)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
anser: 1.4.10
|
anser: 1.4.10
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
@@ -5226,7 +5244,7 @@ snapshots:
|
|||||||
'@expo/json-file': 10.2.0
|
'@expo/json-file': 10.2.0
|
||||||
'@react-native/normalize-colors': 0.81.5
|
'@react-native/normalize-colors': 0.81.5
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
semver: 7.8.5
|
semver: 7.8.5
|
||||||
xml2js: 0.6.0
|
xml2js: 0.6.0
|
||||||
@@ -6287,7 +6305,7 @@ snapshots:
|
|||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@babel/runtime': 7.29.7
|
'@babel/runtime': 7.29.7
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -6743,9 +6761,9 @@ snapshots:
|
|||||||
'@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
|
||||||
'@typescript-eslint/parser': 8.67.0(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/parser': 8.67.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5)
|
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5)
|
||||||
eslint-plugin-expo: 1.1.0(eslint@9.39.5)(typescript@5.9.3)
|
eslint-plugin-expo: 1.1.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
|
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5)
|
||||||
eslint-plugin-react: 7.37.5(eslint@9.39.5)
|
eslint-plugin-react: 7.37.5(eslint@9.39.5)
|
||||||
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.5)
|
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.5)
|
||||||
globals: 16.5.0
|
globals: 16.5.0
|
||||||
@@ -6763,7 +6781,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5):
|
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nolyfill/is-core-module': 1.0.39
|
'@nolyfill/is-core-module': 1.0.39
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
@@ -6774,18 +6792,18 @@ snapshots:
|
|||||||
tinyglobby: 0.2.17
|
tinyglobby: 0.2.17
|
||||||
unrs-resolver: 1.12.2
|
unrs-resolver: 1.12.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
|
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5):
|
eslint-module-utils@2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 8.67.0(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/parser': 8.67.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
eslint-import-resolver-node: 0.3.10
|
eslint-import-resolver-node: 0.3.10
|
||||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5)
|
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -6798,7 +6816,7 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5):
|
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rtsao/scc': 1.1.0
|
'@rtsao/scc': 1.1.0
|
||||||
array-includes: 3.1.9
|
array-includes: 3.1.9
|
||||||
@@ -6809,7 +6827,7 @@ snapshots:
|
|||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
eslint-import-resolver-node: 0.3.10
|
eslint-import-resolver-node: 0.3.10
|
||||||
eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
|
eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.67.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5)
|
||||||
hasown: 2.0.4
|
hasown: 2.0.4
|
||||||
is-core-module: 2.16.2
|
is-core-module: 2.16.2
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
@@ -6930,7 +6948,7 @@ snapshots:
|
|||||||
expo-asset@12.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3):
|
expo-asset@12.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@expo/image-utils': 0.8.15(typescript@5.9.3)
|
'@expo/image-utils': 0.8.15(typescript@5.9.3)
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
expo-constants: 18.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
expo-constants: 18.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
@@ -6942,30 +6960,30 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@expo/config': 12.0.14
|
'@expo/config': 12.0.14
|
||||||
'@expo/env': 2.0.12
|
'@expo/env': 2.0.12
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
expo-file-system@19.0.23(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
expo-file-system@19.0.23(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
expo-font@14.0.12(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
expo-font@14.0.12(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
fontfaceobserver: 2.3.0
|
fontfaceobserver: 2.3.0
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
expo-haptics@15.0.8(expo@54.0.36):
|
expo-haptics@15.0.8(expo@54.0.36):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
|
|
||||||
expo-image@3.0.11(expo@54.0.36)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
expo-image@3.0.11(expo@54.0.36)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -6973,7 +6991,7 @@ snapshots:
|
|||||||
|
|
||||||
expo-keep-awake@15.0.8(expo@54.0.36)(react@19.1.0):
|
expo-keep-awake@15.0.8(expo@54.0.36)(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
|
|
||||||
expo-linking@8.0.12(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
expo-linking@8.0.12(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||||
@@ -7012,7 +7030,7 @@ snapshots:
|
|||||||
client-only: 0.0.1
|
client-only: 0.0.1
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
expo-constants: 18.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
expo-constants: 18.0.13(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))
|
||||||
expo-linking: 8.0.12(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
expo-linking: 8.0.12(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
expo-server: 1.0.7
|
expo-server: 1.0.7
|
||||||
@@ -7043,12 +7061,18 @@ snapshots:
|
|||||||
- '@types/react-dom'
|
- '@types/react-dom'
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
expo-sensors@15.0.8(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
||||||
|
dependencies:
|
||||||
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
|
invariant: 2.2.4
|
||||||
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
expo-server@1.0.7: {}
|
expo-server@1.0.7: {}
|
||||||
|
|
||||||
expo-splash-screen@31.0.13(expo@54.0.36)(typescript@5.9.3):
|
expo-splash-screen@31.0.13(expo@54.0.36)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@expo/prebuild-config': 54.0.9(expo@54.0.36)(typescript@5.9.3)
|
'@expo/prebuild-config': 54.0.9(expo@54.0.36)(typescript@5.9.3)
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
@@ -7061,7 +7085,7 @@ snapshots:
|
|||||||
|
|
||||||
expo-symbols@1.0.8(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
expo-symbols@1.0.8(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
sf-symbols-typescript: 2.2.0
|
sf-symbols-typescript: 2.2.0
|
||||||
|
|
||||||
@@ -7069,7 +7093,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@react-native/normalize-colors': 0.81.5
|
'@react-native/normalize-colors': 0.81.5
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -7078,10 +7102,10 @@ snapshots:
|
|||||||
|
|
||||||
expo-web-browser@15.0.11(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
expo-web-browser@15.0.11(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
expo: 54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
|
||||||
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
expo@54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3):
|
expo@54.0.36(@babel/core@7.29.7)(@expo/metro-runtime@6.1.2)(expo-router@6.0.24)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.29.7
|
'@babel/runtime': 7.29.7
|
||||||
'@expo/cli': 54.0.26(expo-router@6.0.24)(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(typescript@5.9.3)
|
'@expo/cli': 54.0.26(expo-router@6.0.24)(expo@54.0.36)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(typescript@5.9.3)
|
||||||
@@ -7108,6 +7132,7 @@ snapshots:
|
|||||||
whatwg-url-without-unicode: 8.0.0-3
|
whatwg-url-without-unicode: 8.0.0-3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@expo/metro-runtime': 6.1.2(expo@54.0.36)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
'@expo/metro-runtime': 6.1.2(expo@54.0.36)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
|
react-native-webview: 13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- bufferutil
|
- bufferutil
|
||||||
@@ -8520,6 +8545,13 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
|
|
||||||
|
react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
invariant: 2.2.4
|
||||||
|
react: 19.1.0
|
||||||
|
react-native: 0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
react-native-worklets@0.5.1(@babel/core@7.29.7)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
react-native-worklets@0.5.1(@babel/core@7.29.7)(react-native@0.81.5(@babel/core@7.29.7)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.7
|
'@babel/core': 7.29.7
|
||||||
|
|||||||
Reference in New Issue
Block a user