Commit 4c6160de authored by Stoll's avatar Stoll
Browse files

Fix: Emojis loaded correctly

parent 98fab318
import React from "react";
interface ScreenshotButtonProps {
mountRef: React.RefObject<HTMLDivElement | null>;
overlayRef: React.RefObject<HTMLDivElement | null>;
reticleRef?: React.RefObject<any>; // Optional if you have a reticle
}
const ScreenshotButton: React.FC<ScreenshotButtonProps> = ({
mountRef,
overlayRef,
reticleRef,
}) => {
const captureAndDownload = () => {
const canvas =
(mountRef.current?.querySelector("canvas") ||
document.querySelector("canvas")) as HTMLCanvasElement | null;
if (!canvas || !overlayRef.current) return;
const overlayEl = overlayRef.current;
const prevPointer = overlayEl.style.pointerEvents;
const prevOpacity = overlayEl.style.opacity;
overlayEl.style.pointerEvents = "none";
overlayEl.style.opacity = "0";
const reticle = reticleRef?.current;
const prevReticleVisible = reticle?.visible ?? false;
if (reticle) reticle.visible = false;
requestAnimationFrame(() => {
canvas.toBlob((blob) => {
overlayEl.style.pointerEvents = prevPointer;
overlayEl.style.opacity = prevOpacity;
if (reticle) reticle.visible = prevReticleVisible;
if (!blob) return;
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
const ts = new Date().toISOString().replace(/[:.]/g, "-");
a.href = url;
a.download = `ar-snapshot-${ts}.png`;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}, "image/png");
});
};
return (
<button
onClick={captureAndDownload}
aria-label="Save snapshot"
style={{
position: "absolute",
top: "4rem",
right: "1.5rem",
zIndex: 1000,
padding: "10px 12px",
borderRadius: 12,
border: "none",
background: "white",
fontSize: 18,
boxShadow: "0 2px 8px rgba(0,0,0,0.25)",
cursor: "pointer",
}}
>
📷
</button>
);
};
export default ScreenshotButton;
...@@ -10,6 +10,7 @@ import {ARBottomBar} from "./ARBottomBar"; ...@@ -10,6 +10,7 @@ import {ARBottomBar} from "./ARBottomBar";
import {RoomEnvironment} from "three/examples/jsm/environments/RoomEnvironment"; import {RoomEnvironment} from "three/examples/jsm/environments/RoomEnvironment";
import {addLightToScene, createCamera, createPlacementRing, createRenderer, setSceneBackground} from "./Setup.ts"; import {addLightToScene, createCamera, createPlacementRing, createRenderer, setSceneBackground} from "./Setup.ts";
import ScreenshotButton from "./ScreenshotButton.tsx"; // bottom UI for selecting objects
import {ModelEmojiMap, ModelName, ModelTypeMap} from "../model/ModelType.ts"; // bottom UI for selecting objects import {ModelEmojiMap, ModelName, ModelTypeMap} from "../model/ModelType.ts"; // bottom UI for selecting objects
...@@ -139,7 +140,7 @@ export const XRRenderer: React.FC = () => { ...@@ -139,7 +140,7 @@ export const XRRenderer: React.FC = () => {
if (name === ModelName.CUBE) { if (name === ModelName.CUBE) {
objectToAdd = new Cube(position); objectToAdd = new Cube(position);
} else { } else {
objectToAdd = new GLTFModel(`/${ModelTypeMap[name as ModelName]}/${name}.glb`, position, `/${ModelTypeMap[name as ModelName]}/colormap.png`) objectToAdd = new GLTFModel(`/${ModelTypeMap[name as ModelName]}/${name.toLowerCase().replace(/\s/g, "")}.glb`, position, `/${ModelTypeMap[name as ModelName]}/colormap.png`)
} }
const audio = new Audio('/sounds/cash.mp3'); const audio = new Audio('/sounds/cash.mp3');
...@@ -164,62 +165,23 @@ export const XRRenderer: React.FC = () => { ...@@ -164,62 +165,23 @@ export const XRRenderer: React.FC = () => {
}; };
}, []); // empty dependency array → runs only once }, []); // empty dependency array → runs only once
// --- 🔸 Screenshot function ---
const captureAndDownload = () => {
// Get the <canvas> element from the renderer
const canvas = (mountRef.current?.querySelector("canvas") ||
document.querySelector("canvas")) as HTMLCanvasElement | null;
if (!canvas || !overlayRef.current) return;
// Hide UI overlay for a clean capture
const overlayEl = overlayRef.current;
const prevPointer = overlayEl.style.pointerEvents;
const prevOpacity = overlayEl.style.opacity;
overlayEl.style.pointerEvents = "none";
overlayEl.style.opacity = "0";
// Hide reticle (optional)
const reticle = reticleRef.current;
const prevReticleVisible = reticle?.visible ?? false;
if (reticle) reticle.visible = false;
// Wait one frame → take screenshot
requestAnimationFrame(() => {
canvas.toBlob((blob) => {
// Restore UI and reticle visibility
overlayEl.style.pointerEvents = prevPointer;
overlayEl.style.opacity = prevOpacity;
if (reticle) reticle.visible = prevReticleVisible;
if (!blob) return;
// Create download link
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
const ts = new Date().toISOString().replace(/[:.]/g, "-");
a.href = url;
a.download = `ar-snapshot-${ts}.png`;
document.body.appendChild(a);
a.click(); // trigger download
a.remove();
URL.revokeObjectURL(url);
}, "image/png");
});
};
// --- 🔸 Handle user selection from bottom bar --- // --- 🔸 Handle user selection from bottom bar ---
const handleSelect = (name: string) => { const handleSelect = (name: string) => {
setSelectedObject(name); // update state setSelectedObject(name); // update state
(window as any).addSelectedObject?.(name); // add object immediately (window as any).addSelectedObject?.(name); // add object immediately
}; };
const items = []; const items: { name: string; emoji: string; }[] | { name: ModelName; emoji: string; }[] = [];
for (const key in ModelName) { (Object.keys(ModelName) as Array<keyof typeof ModelName>).forEach((key) => {
const model = ModelName[key];
items.push({ items.push({
name: ModelName[key as keyof typeof ModelName], name: model,
emoji: ModelEmojiMap[key as keyof typeof ModelEmojiMap], emoji: ModelEmojiMap[model],
}); });
} });
console.log(items);
// --- 🔸 Render layout --- // --- 🔸 Render layout ---
return ( return (
...@@ -232,26 +194,9 @@ for (const key in ModelName) { ...@@ -232,26 +194,9 @@ for (const key in ModelName) {
ref={overlayRef} ref={overlayRef}
style={{ position: "absolute", width: "100%", height: "100%" }} style={{ position: "absolute", width: "100%", height: "100%" }}
> >
{/* 📷 Screenshot button (top-right corner) */} {/* Screenshot button moved to its own component */}
<button <ScreenshotButton mountRef={mountRef} overlayRef={overlayRef} reticleRef={reticleRef} />
onClick={captureAndDownload}
aria-label="Save snapshot"
style={{
position: "absolute",
top: "4rem",
right: "1.5rem",
zIndex: 1000,
padding: "10px 12px",
borderRadius: 12,
border: "none",
background: "white",
fontSize: 18,
boxShadow: "0 2px 8px rgba(0,0,0,0.25)",
cursor: "pointer",
}}
>
📷
</button>
{/* Bottom bar appears only during active AR session */} {/* Bottom bar appears only during active AR session */}
{/*{isSessionActive && (*/} {/*{isSessionActive && (*/}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment