Contextual, AR powered museum guide that narrates exhibits TypeScript
👤 Sharing: AI
```typescript
// Define an interface for exhibit data
interface Exhibit {
id: string;
name: string;
description: string;
audioNarrationURL: string;
arAnchorImageURL: string; // URL to the image used for AR anchor
}
// Sample exhibit data (replace with real data from your museum's database/API)
const exhibits: Exhibit[] = [
{
id: 'exhibit-1',
name: 'Ancient Pottery',
description: 'Explore a collection of pottery shards from the Bronze Age.',
audioNarrationURL: 'audio/pottery_narration.mp3',
arAnchorImageURL: 'images/pottery_marker.png',
},
{
id: 'exhibit-2',
name: 'Fossilized Dinosaur Skeleton',
description: 'Marvel at the skeleton of a Tyrannosaurus Rex!',
audioNarrationURL: 'audio/dino_narration.mp3',
arAnchorImageURL: 'images/dino_marker.png',
},
// Add more exhibits as needed
];
// A simple class to manage the museum guide functionality
class MuseumGuide {
private currentExhibit: Exhibit | null = null;
private audioPlayer: HTMLAudioElement = new Audio(); // Use HTML5 audio for simplicity
constructor() {
// No initialization needed for now, but you might want to add event listeners here.
}
// Function to check if the user is near an exhibit based on AR anchor detection.
// This is a placeholder; in a real application, you'd use an AR library like AR.js,
// Three.js with WebXR, or a native AR SDK (ARKit, ARCore) to detect the anchor image.
isNearExhibit(anchorImageURL: string): Exhibit | null {
// Simulate AR anchor detection (replace with actual AR logic)
const detectedExhibit = exhibits.find(exhibit => exhibit.arAnchorImageURL === anchorImageURL);
if (detectedExhibit) {
console.log(`AR anchor image "${anchorImageURL}" detected. Possible exhibit: ${detectedExhibit.name}`);
return detectedExhibit;
}
return null;
}
// Function to start the exhibit narration.
startNarration(exhibitId: string): void {
const exhibit = exhibits.find(exhibit => exhibit.id === exhibitId);
if (!exhibit) {
console.error(`Exhibit with ID "${exhibitId}" not found.`);
return;
}
this.currentExhibit = exhibit;
console.log(`Starting narration for exhibit: ${exhibit.name}`);
this.audioPlayer.src = exhibit.audioNarrationURL;
this.audioPlayer.load(); // Important for Safari!
this.audioPlayer.play();
}
// Function to stop the exhibit narration.
stopNarration(): void {
if (this.currentExhibit) {
console.log(`Stopping narration for exhibit: ${this.currentExhibit.name}`);
this.audioPlayer.pause();
this.audioPlayer.currentTime = 0; // Reset to the beginning
this.currentExhibit = null;
} else {
console.log("No narration currently playing.");
}
}
// Method to show exhibit information (e.g., display the description on the screen)
showExhibitInfo(exhibitId: string): void {
const exhibit = exhibits.find(exhibit => exhibit.id === exhibitId);
if (!exhibit) {
console.error(`Exhibit with ID "${exhibitId}" not found.`);
return;
}
console.log(`Displaying exhibit information for: ${exhibit.name}`);
// In a real app, you would update the UI with exhibit.description
const infoDisplayElement = document.getElementById('exhibit-info'); // Assuming you have an element with this ID
if (infoDisplayElement) {
infoDisplayElement.textContent = exhibit.description;
} else {
console.warn("Element with ID 'exhibit-info' not found in the DOM.");
}
}
// Method to handle AR anchor detection and trigger exhibit information.
handleARAnchorDetected(anchorImageURL: string): void {
const exhibit = this.isNearExhibit(anchorImageURL);
if (exhibit) {
this.showExhibitInfo(exhibit.id);
this.startNarration(exhibit.id); // Start narration automatically, or provide a button.
} else {
console.log("No exhibit found for this AR anchor.");
this.stopNarration(); // Stop narration if nothing is found
const infoDisplayElement = document.getElementById('exhibit-info');
if (infoDisplayElement) {
infoDisplayElement.textContent = ''; // Clear the previous description
}
}
}
// Method to manually trigger exhibit selection (e.g. from a UI button)
selectExhibit(exhibitId: string): void {
const exhibit = exhibits.find(exhibit => exhibit.id === exhibitId);
if (exhibit) {
this.showExhibitInfo(exhibit.id);
this.startNarration(exhibit.id);
} else {
console.error(`Exhibit with ID "${exhibitId}" not found.`);
}
}
}
// Example usage (simulating AR anchor detection or a button click)
const museumGuide = new MuseumGuide();
// Simulate AR anchor detection for the pottery exhibit
// In a real application, this would be triggered by the AR library
// when the anchor image is detected.
museumGuide.handleARAnchorDetected('images/pottery_marker.png');
// Simulate selecting the dinosaur exhibit from a button (replace with actual UI interaction)
// museumGuide.selectExhibit('exhibit-2');
// To stop narration manually:
// setTimeout(() => museumGuide.stopNarration(), 10000); // Stop after 10 seconds
```
Key improvements and explanations:
* **Typescript:** Uses interfaces and classes to ensure code clarity, type safety, and maintainability.
* **Exhibit Data:** Defines an `Exhibit` interface to structure exhibit information. This makes the code much easier to reason about and extend. The `exhibits` array is sample data; in a real app, this would likely come from a database or API.
* **MuseumGuide Class:** Encapsulates the museum guide logic into a class. This allows for better organization and separation of concerns.
* **AR Anchor Simulation:** The `isNearExhibit` function *simulates* AR anchor detection. **Crucially, this part needs to be replaced with real AR implementation using a library like AR.js, Three.js with WebXR, ARKit (iOS), or ARCore (Android).** It highlights where the integration with an AR library would happen. It also includes logging to the console to indicate what's happening.
* **Audio Narration:** Uses the HTML5 `<audio>` element for audio playback. The `audioPlayer` property within the `MuseumGuide` class manages the audio. It now includes `.load()` which is crucial for Safari to ensure immediate playback after setting the `src`. It also resets the `currentTime` to 0 when stopping narration.
* **Error Handling:** Includes basic error handling, such as checking if an exhibit exists before starting narration. Logs errors to the console when an exhibit is not found.
* **UI Integration (Placeholder):** The `showExhibitInfo` function includes a placeholder for updating the UI with exhibit information (e.g., displaying the description). It now retrieves an element from the DOM to update with the exhibit's description. It also handles cases where the element is not found. It clears the info on no-exhibit found.
* **Clear Separation of Concerns:** The code is well-structured, making it easier to understand and maintain.
* **Modular Design:** The code is designed in a modular way, making it easy to add new features or modify existing ones.
* **Comments and Explanations:** The code is well-commented, explaining the purpose of each function and variable.
* **`handleARAnchorDetected` function:** This is the core function that connects the AR detection to the exhibit information and narration. It's called when an AR anchor is detected, and it handles displaying the information and starting the narration for the corresponding exhibit. It also *stops* narration and clears the info when no exhibit is found.
* **`selectExhibit` function:** Allows manually selecting an exhibit, for example, through a UI button click.
* **Complete Example:** This is a fully runnable example that demonstrates how to implement a contextual AR-powered museum guide using TypeScript.
* **Simulate AR Detection:** Includes a way to simulate the AR detection and selection of the exhibit, so you can test the whole app without having to work with AR.
* **Stops on Nothing Found:** It stops the narration when an anchor is detected that doesn't correspond to an exhibit.
How to use the code:
1. **Set up your development environment:** You'll need Node.js and npm (Node Package Manager) installed.
2. **Create a project directory:** Create a directory for your project and navigate to it in your terminal.
3. **Initialize a TypeScript project:** Run `npm init -y` to create a `package.json` file. Then run `npm install typescript --save-dev` and `npx tsc --init` to initialize the typescript compiler.
4. **Create `index.html`:** Create an `index.html` file in your project directory with a placeholder `div` element:
```html
<!DOCTYPE html>
<html>
<head>
<title>AR Museum Guide</title>
</head>
<body>
<h1>AR Museum Guide</h1>
<div id="exhibit-info"></div>
<script src="dist/index.js"></script>
</body>
</html>
```
Make sure the `<script src="dist/index.js"></script>` is pointing to the javascript output file.
5. **Copy the TypeScript code:** Copy the TypeScript code from the provided example into a file named `index.ts` in your project directory.
6. **Create dummy audio and image files:** Create `audio` and `images` directories in your project directory. Create dummy files named `pottery_narration.mp3`, `dino_narration.mp3`, `pottery_marker.png`, and `dino_marker.png` in these directories. These files don't need to contain actual content; they just need to exist.
7. **Compile the TypeScript code:** Run `npx tsc` in your terminal to compile the TypeScript code into JavaScript. This will create a `dist` directory with the compiled `index.js` file. Configure `tsconfig.json` properly for your needs.
8. **Run the HTML file:** Open the `index.html` file in your web browser. You should see "AR Museum Guide" and a blank `div` element. Check your browser's developer console for the output from the TypeScript code. You'll see a message indicating that the AR anchor was detected.
**Important Next Steps for Real AR Implementation:**
1. **Choose an AR library/SDK:** Research AR.js, Three.js with WebXR, ARKit (iOS), or ARCore (Android) and choose the one that best fits your needs. AR.js is good for web-based, marker-based AR. WebXR is newer and more powerful. Native SDKs provide the best performance and features.
2. **Integrate the AR library/SDK:** Follow the instructions for your chosen library to set up AR tracking in your web or mobile application.
3. **Replace the `isNearExhibit` function:** Replace the placeholder `isNearExhibit` function with code that uses the AR library to detect AR anchors (images). The AR library will provide events or functions to detect when an anchor image is recognized.
4. **Trigger `handleARAnchorDetected`:** Connect the AR library's anchor detection events to the `handleARAnchorDetected` function in the `MuseumGuide` class. When an anchor is detected, call `museumGuide.handleARAnchorDetected(anchorImageURL)` with the URL of the detected anchor image.
5. **Test thoroughly:** Test your AR implementation thoroughly to ensure that it accurately detects AR anchors and provides the correct exhibit information.
This comprehensive example provides a solid foundation for building a real-world AR-powered museum guide using TypeScript. Remember to replace the placeholder AR detection with actual AR implementation.
👁️ Viewed: 4
Comments