Create your first application
This guide will walk you through the steps to create a simple web application that displays an interactive map using the Magic Lane Maps SDK for TypeScript.
For this guide you will need an API key - follow our step-by-step guide to sign up for a free account, create a project and generate your API key.
Create a New Project
We'll use Vite for this example, as it provides the best development experience with fast HMR and optimized builds.
# Create a new Vite project with TypeScript
npm create vite@latest my-first-map-app -- --template vanilla-ts
# Navigate to the project directory
cd my-first-map-app
# Install dependencies
npm install
# Install the Maps SDK
npm install @magiclane/maps-sdk
If you already have a project, you can skip the project creation step and just install the SDK.
Project Structure
Your project should have the following structure:
my-first-map-app/
├── public/
├── src/
│ ├── main.ts
│ └── style.css
├── index.html
├── package.json
├── tsconfig.json
└── vite.config.ts
Configure Vite
Create or update vite.config.ts to support WebAssembly:
import { defineConfig } from 'vite';
export default defineConfig({
server: {
port: 3000,
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
}
},
optimizeDeps: {
exclude: ['@magiclane/maps-sdk']
}
});
Setup Environment Variables
Create a .env file in the root of your project:
VITE_MAGICLANE_API_TOKEN=your_api_token_here
Don't forget to add .env to your .gitignore file to avoid committing your API token to version control!
HTML Setup
Update index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My First Map App</title>
</head>
<body>
<div id="app">
<div id="map-container"></div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
CSS Styling
Update src/style.css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
#app {
width: 100%;
height: 100%;
display: flex;
overflow: hidden;
flex-direction: column;
}
#map-container {
flex: 1;
width: 100%;
position: relative;
overflow: hidden;
background: #f0f0f0;
}
TypeScript Code
Update src/main.ts:
import './style.css';
import { GemKit, GemMap } from '@magiclane/maps-sdk';
// Get API token from environment variable
const apiToken = import.meta.env.VITE_MAGICLANE_API_TOKEN;
// Main initialization function
async function initializeMap() {
try {
// Validate API token
if (!apiToken) {
throw new Error(
'API token not found. Please set VITE_MAGICLANE_API_TOKEN in your .env file'
);
}
// Initialize GemKit with your API token
console.log('Initializing GemKit...');
const gemKit = await GemKit.initialize(apiToken);
console.log('GemKit initialized successfully!');
// Get the map container element
const container = document.getElementById('map-container');
if (!container) {
throw new Error('Map container not found');
}
// Create the map view
const viewId = 1;
const wrapper = gemKit.createView(viewId, (gemMap: GemMap) => {
console.log('Map created successfully!');
// Map is ready - you can perform additional operations here
onMapReady(gemMap);
});
if (wrapper) {
container.appendChild(wrapper);
} else {
throw new Error('Failed to create map view');
}
} catch (error) {
console.error('Failed to initialize map:', error);
showError(error instanceof Error ? error.message : 'Unknown error occurred');
}
}
// Callback when map is ready
function onMapReady(gemMap: GemMap) {
console.log('Map is ready for interaction');
// You can add custom logic here, such as:
// - Setting initial map position
// - Adding markers
// - Setting up event listeners
// - Configuring map preferences
}
// Error display function
function showError(message: string) {
const container = document.getElementById('map-container');
if (container) {
container.innerHTML = `
<div style="
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 20px;
text-align: center;
color: #d32f2f;
">
<div>
<h2>Error Loading Map</h2>
<p style="margin-top: 10px;">${message}</p>
</div>
</div>
`;
}
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeMap);
} else {
initializeMap();
}
Run Your Application
Start the development server:
npm run dev
Open your browser and navigate to http://localhost:3000. You should see an interactive map displayed in your browser!
Build for Production
When you're ready to deploy your application:
npm run build
This creates an optimized production build in the dist directory.
Key Points
- Initialization: The SDK must be initialized with
GemKit.initialize()before creating any maps - Async Loading: Map initialization is asynchronous, so always use
async/awaitor promises - Container Requirements: The map container must have explicit width and height (we use flex layout in this example)
- Environment Variables: Always use environment variables for API tokens, never hardcode them
- Error Handling: Implement proper error handling to provide user feedback if initialization fails
If the API key is not configured correctly, some features will be restricted, and a watermark will appear on the map. Features such as map downloads, updates, and other functionality may be unavailable or may not function as expected. Ensure your API token is set correctly and stored securely.