Skip to main content

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
important

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/await or 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
warning

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.