From 1f2601a1edf8334e9ab302f0025bf2cdb812aebf Mon Sep 17 00:00:00 2001 From: Mark Kalsbeek Date: Tue, 20 Jan 2026 22:00:49 +0100 Subject: [PATCH] first map setup --- .envrc | 1 + .gitignore | 52 +++ requirements.txt | 4 + shell.nix | 71 +++++ tooling/las2mound.py | 159 +++++++++ ui/deno.json | 17 + ui/deno.lock | 745 +++++++++++++++++++++++++++++++++++++++++++ ui/index.html | 12 + ui/public/tiles | 1 + ui/src/App.vue | 395 +++++++++++++++++++++++ ui/src/main.js | 6 + ui/vite.config.js | 55 ++++ 12 files changed, 1518 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 requirements.txt create mode 100644 shell.nix create mode 100644 tooling/las2mound.py create mode 100644 ui/deno.json create mode 100644 ui/deno.lock create mode 100644 ui/index.html create mode 120000 ui/public/tiles create mode 100644 ui/src/App.vue create mode 100644 ui/src/main.js create mode 100644 ui/vite.config.js diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5000f4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Temporary files, for example, from tests. +/tmp/ + +# Ignore package tarball (built via "mix hex.build"). +docmark-*.tar + +docs/*.pdf +data + +# Ignore assets that are produced by build tools. +/priv/static/assets/ +/priv/static/*.js +/priv/static/*.html +/priv/static/*.css + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ +/ui/node_modules/ +/ui/.vite/ + +*.sublime* + +postgres +.direnv + +# Generated code: +ui/src/types/api.ts \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e9bb933 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +laspy>=2.0.0 +scipy>=1.9.0 +numpy>=1.21.0 +pyproj>=3.0.0 \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..4b8aecd --- /dev/null +++ b/shell.nix @@ -0,0 +1,71 @@ +# shell.nix +/* +# Dev env for elixir + + +## Environment Variables + +- MIX_HOME: Local Mix installation +- HEX_HOME: Local Hex package manager +- PGDIR: PostgreSQL data directory +- PGHOST: Unix domain socket location +- DATABASE_URL: PostgreSQL connection string +*/ + +let + # Import nixos-unstable for most packages + pkgs = import {}; + # Import nixpkgs-unstable for outliers + pkgs-unstable = import {}; + + extraPackages = [ + pkgs.beam.packages.erlang_27.elixir_1_18 + pkgs.beam.packages.erlang_27.erlang + pkgs.elixir_ls + pkgs.inotify-tools + + # DB + pkgs.postgresql + # JS + pkgs-unstable.deno + # PY + pkgs.python3 + pkgs.python3Packages.laspy + pkgs.python3Packages.scipy + pkgs.python3Packages.numpy + pkgs.python3Packages.pyproj + ]; + + mkShell = pkgs.mkShell; + PROJECT_ROOT = builtins.toString ./.; + + hooks = '' + # Set up environment variables + + # PostgreSQL configuration + export PGDIR=${PROJECT_ROOT}/postgres + export PGHOST=$PGDIR + export PGDATA=$PGDIR/data + export PGLOG=$PGDIR/log + export DATABASE_URL="postgresql:///postgres?host=$PGDIR" + + # Create PostgreSQL directories if they don't exist + if test ! -d $PGDIR; then + mkdir $PGDIR + fi + + if [ ! -d $PGDATA ]; then + echo 'Initializing postgresql database...' + initdb $PGDATA --auth=trust >/dev/null + fi + + # Print setup instructions + echo "Elixir development environment ready!" + echo "To start PostgreSQL, run: postgres -h \'\' -k \'$PGHOST\'" + echo "To start the project, run : iex -S mix phx.server" + ''; + +in mkShell { + buildInputs = extraPackages; + shellHook = hooks; +} diff --git a/tooling/las2mound.py b/tooling/las2mound.py new file mode 100644 index 0000000..10f5157 --- /dev/null +++ b/tooling/las2mound.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Convert LAS lidar files to .mound binary format for Three.js rendering. + +Usage: + python las_to_mound.py input.las output.mound +""" + +import sys +import struct +import numpy as np +from pathlib import Path + +try: + import laspy +except ImportError: + print("Error: laspy not installed. Run: pip install laspy") + sys.exit(1) + +try: + from scipy.spatial import Delaunay +except ImportError: + print("Error: scipy not installed. Run: pip install scipy") + sys.exit(1) + +try: + from pyproj import Transformer +except ImportError: + print("Error: pyproj not installed. Run: pip install pyproj") + sys.exit(1) + + +def transform_to_latlon(x, y, z): + """Transform Ohio State Plane coordinates to lat/lon.""" + print("Transforming coordinates to lat/lon...") + + # Ohio State Plane South (EPSG:3735) in US Survey Feet to WGS84 (EPSG:4326) + # Note: Ohio has two zones - North (3734) and South (3735) + # Newark is in the North zone + transformer = Transformer.from_crs("EPSG:3734", "EPSG:4326", always_xy=True) + + # Transform x,y (easting, northing) to lon, lat + lon, lat = transformer.transform(x, y) + + # Convert elevation from US Survey Feet to meters + z_meters = z * 0.3048006096012192 + + print(f"Transformed to lat/lon bounds: lon[{lon.min():.6f}, {lon.max():.6f}] lat[{lat.min():.6f}, {lat.max():.6f}]") + + return lon, lat, z_meters + + +def read_las(filepath): + """Read LAS file and extract ground points.""" + print(f"Reading {filepath}...") + las = laspy.read(filepath) + + # Extract coordinates + x = las.x + y = las.y + z = las.z + + # Filter for ground points (classification 2) if available + if hasattr(las, 'classification'): + ground_mask = las.classification == 2 + if ground_mask.any(): + print(f"Filtering {ground_mask.sum()} ground points from {len(x)} total points") + x = x[ground_mask] + y = y[ground_mask] + z = z[ground_mask] + + print(f"Loaded {len(x)} points") + return x, y, z + + +def triangulate_points(x, y, z): + """Perform Delaunay triangulation on XY coordinates.""" + print("Performing Delaunay triangulation...") + + # Create 2D point array for triangulation + points_2d = np.column_stack([x, y]) + + # Triangulate + tri = Delaunay(points_2d) + + print(f"Generated {len(tri.simplices)} triangles") + + return tri.simplices + + +def write_mound(filepath, x, y, z, indices): + """Write .mound binary format.""" + print(f"Writing {filepath}...") + + # Convert to float32 + positions = np.column_stack([x, y, z]).astype(np.float32) + indices = indices.astype(np.uint32) + + # Calculate bounds + min_x, min_y, min_z = positions.min(axis=0) + max_x, max_y, max_z = positions.max(axis=0) + + point_count = len(positions) + triangle_count = len(indices) + + with open(filepath, 'wb') as f: + # Header (64 bytes) + f.write(b'LIDR') # Magic number (4 bytes) + f.write(struct.pack('I', 1)) # Version (4 bytes) + f.write(struct.pack('I', point_count)) # Point count (4 bytes) + f.write(struct.pack('I', triangle_count)) # Triangle count (4 bytes) + f.write(struct.pack('f', min_x)) # Min X (4 bytes) + f.write(struct.pack('f', min_y)) # Min Y (4 bytes) + f.write(struct.pack('f', min_z)) # Min Z (4 bytes) + f.write(struct.pack('f', max_x)) # Max X (4 bytes) + f.write(struct.pack('f', max_y)) # Max Y (4 bytes) + f.write(struct.pack('f', max_z)) # Max Z (4 bytes) + f.write(b'\x00' * 24) # Reserved (24 bytes) + + # Position data + f.write(positions.tobytes()) + + # Index data + f.write(indices.tobytes()) + + file_size = Path(filepath).stat().st_size / (1024 * 1024) + print(f"Wrote {point_count} points, {triangle_count} triangles ({file_size:.2f} MB)") + print(f"Bounds: X[{min_x:.2f}, {max_x:.2f}] Y[{min_y:.2f}, {max_y:.2f}] Z[{min_z:.2f}, {max_z:.2f}]") + + +def main(): + if len(sys.argv) != 3: + print("Usage: python las_to_mound.py input.las output.mound") + sys.exit(1) + + input_file = sys.argv[1] + output_file = sys.argv[2] + + if not Path(input_file).exists(): + print(f"Error: Input file '{input_file}' not found") + sys.exit(1) + + # Read LAS + x, y, z = read_las(input_file) + + # Transform to lat/lon + lon, lat, z_meters = transform_to_latlon(x, y, z) + + # Triangulate (using lon/lat as x/y) + indices = triangulate_points(lon, lat, z_meters) + + # Write output (lon as x, lat as y, elevation as z) + write_mound(output_file, lon, lat, z_meters, indices) + + print("Done!") + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/ui/deno.json b/ui/deno.json new file mode 100644 index 0000000..d510699 --- /dev/null +++ b/ui/deno.json @@ -0,0 +1,17 @@ +{ + "imports": { + "@vitejs/plugin-vue": "npm:@vitejs/plugin-vue@^5", + "maplibre-gl": "npm:maplibre-gl@^5.16.0", + "three": "npm:three@^0.182.0", + "vite": "npm:vite@^7.2.1", + "vue": "npm:vue@^3.5.23", + "pinia": "npm:pinia@^3.0.4", + }, + "tasks": { + "dev": "deno run -A --node-modules-dir npm:vite", + "build": "deno run -A --node-modules-dir npm:vite build", + "watch": "deno run -A --node-modules-dir npm:vite build --watch", + "preview": "deno run -A --node-modules-dir npm:vite preview", + }, + "nodeModulesDir": "auto" +} diff --git a/ui/deno.lock b/ui/deno.lock new file mode 100644 index 0000000..0ca909e --- /dev/null +++ b/ui/deno.lock @@ -0,0 +1,745 @@ +{ + "version": "5", + "specifiers": { + "npm:@vitejs/plugin-vue@5": "5.2.4_vite@7.2.1__picomatch@4.0.3_vue@3.5.23", + "npm:maplibre-gl@^5.16.0": "5.16.0", + "npm:pinia@^3.0.4": "3.0.4_vue@3.5.23", + "npm:three@0.182": "0.182.0", + "npm:vite@*": "7.2.1_picomatch@4.0.3", + "npm:vite@^7.2.1": "7.2.1_picomatch@4.0.3", + "npm:vue@^3.5.23": "3.5.23" + }, + "npm": { + "@babel/helper-string-parser@7.27.1": { + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier@7.28.5": { + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==" + }, + "@babel/parser@7.28.5": { + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dependencies": [ + "@babel/types" + ], + "bin": true + }, + "@babel/types@7.28.5": { + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dependencies": [ + "@babel/helper-string-parser", + "@babel/helper-validator-identifier" + ] + }, + "@esbuild/aix-ppc64@0.25.12": { + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@esbuild/android-arm64@0.25.12": { + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm@0.25.12": { + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-x64@0.25.12": { + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/darwin-arm64@0.25.12": { + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-x64@0.25.12": { + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-arm64@0.25.12": { + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-x64@0.25.12": { + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/linux-arm64@0.25.12": { + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm@0.25.12": { + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-ia32@0.25.12": { + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-loong64@0.25.12": { + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-mips64el@0.25.12": { + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-ppc64@0.25.12": { + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-riscv64@0.25.12": { + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-s390x@0.25.12": { + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-x64@0.25.12": { + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-arm64@0.25.12": { + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@esbuild/netbsd-x64@0.25.12": { + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-arm64@0.25.12": { + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@esbuild/openbsd-x64@0.25.12": { + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openharmony-arm64@0.25.12": { + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@esbuild/sunos-x64@0.25.12": { + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/win32-arm64@0.25.12": { + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-ia32@0.25.12": { + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-x64@0.25.12": { + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@jridgewell/sourcemap-codec@1.5.5": { + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "@mapbox/geojson-rewind@0.5.2": { + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "dependencies": [ + "get-stream", + "minimist" + ], + "bin": true + }, + "@mapbox/jsonlint-lines-primitives@2.0.2": { + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==" + }, + "@mapbox/point-geometry@1.1.0": { + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==" + }, + "@mapbox/tiny-sdf@2.0.7": { + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==" + }, + "@mapbox/unitbezier@0.0.1": { + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + }, + "@mapbox/vector-tile@2.0.4": { + "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", + "dependencies": [ + "@mapbox/point-geometry", + "@types/geojson", + "pbf" + ] + }, + "@mapbox/whoots-js@3.1.0": { + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" + }, + "@maplibre/maplibre-gl-style-spec@24.4.1": { + "integrity": "sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg==", + "dependencies": [ + "@mapbox/jsonlint-lines-primitives", + "@mapbox/unitbezier", + "json-stringify-pretty-compact", + "minimist", + "quickselect", + "rw", + "tinyqueue" + ], + "bin": true + }, + "@maplibre/mlt@1.1.2": { + "integrity": "sha512-SQKdJ909VGROkA6ovJgtHNs9YXV4YXUPS+VaZ50I2Mt951SLlUm2Cv34x5Xwc1HiFlsd3h2Yrs5cn7xzqBmENw==", + "dependencies": [ + "@mapbox/point-geometry" + ] + }, + "@maplibre/vt-pbf@4.2.0": { + "integrity": "sha512-bxrk/kQUwWXZgmqYgwOCnZCMONCRi3MJMqJdza4T3E4AeR5i+VyMnaJ8iDWtWxdfEAJRtrzIOeJtxZSy5mFrFA==", + "dependencies": [ + "@mapbox/point-geometry", + "@mapbox/vector-tile", + "@types/geojson-vt", + "@types/supercluster", + "geojson-vt", + "pbf", + "supercluster" + ] + }, + "@rollup/rollup-android-arm-eabi@4.52.5": { + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "os": ["android"], + "cpu": ["arm"] + }, + "@rollup/rollup-android-arm64@4.52.5": { + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@rollup/rollup-darwin-arm64@4.52.5": { + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@rollup/rollup-darwin-x64@4.52.5": { + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@rollup/rollup-freebsd-arm64@4.52.5": { + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@rollup/rollup-freebsd-x64@4.52.5": { + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@rollup/rollup-linux-arm-gnueabihf@4.52.5": { + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@rollup/rollup-linux-arm-musleabihf@4.52.5": { + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@rollup/rollup-linux-arm64-gnu@4.52.5": { + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@rollup/rollup-linux-arm64-musl@4.52.5": { + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@rollup/rollup-linux-loong64-gnu@4.52.5": { + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@rollup/rollup-linux-ppc64-gnu@4.52.5": { + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@rollup/rollup-linux-riscv64-gnu@4.52.5": { + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@rollup/rollup-linux-riscv64-musl@4.52.5": { + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@rollup/rollup-linux-s390x-gnu@4.52.5": { + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@rollup/rollup-linux-x64-gnu@4.52.5": { + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@rollup/rollup-linux-x64-musl@4.52.5": { + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@rollup/rollup-openharmony-arm64@4.52.5": { + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@rollup/rollup-win32-arm64-msvc@4.52.5": { + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@rollup/rollup-win32-ia32-msvc@4.52.5": { + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@rollup/rollup-win32-x64-gnu@4.52.5": { + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@rollup/rollup-win32-x64-msvc@4.52.5": { + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@types/estree@1.0.8": { + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" + }, + "@types/geojson-vt@3.2.5": { + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "dependencies": [ + "@types/geojson" + ] + }, + "@types/geojson@7946.0.16": { + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==" + }, + "@types/supercluster@7.1.3": { + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "dependencies": [ + "@types/geojson" + ] + }, + "@vitejs/plugin-vue@5.2.4_vite@7.2.1__picomatch@4.0.3_vue@3.5.23": { + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dependencies": [ + "vite", + "vue" + ] + }, + "@vue/compiler-core@3.5.23": { + "integrity": "sha512-nW7THWj5HOp085ROk65LwaoxuzDsjIxr485F4iu63BoxsXoSqKqmsUUoP4A7Gl67DgIgi0zJ8JFgHfvny/74MA==", + "dependencies": [ + "@babel/parser", + "@vue/shared", + "entities", + "estree-walker", + "source-map-js" + ] + }, + "@vue/compiler-dom@3.5.23": { + "integrity": "sha512-AT8RMw0vEzzzO0JU5gY0F6iCzaWUIh/aaRVordzMBKXRpoTllTT4kocHDssByPsvodNCfump/Lkdow2mT/O5KQ==", + "dependencies": [ + "@vue/compiler-core", + "@vue/shared" + ] + }, + "@vue/compiler-sfc@3.5.23": { + "integrity": "sha512-3QTEUo4qg7FtQwaDJa8ou1CUikx5WTtZlY61rRRDu3lK2ZKrGoAGG8mvDgOpDsQ4A1bez9s+WtBB6DS2KuFCPw==", + "dependencies": [ + "@babel/parser", + "@vue/compiler-core", + "@vue/compiler-dom", + "@vue/compiler-ssr", + "@vue/shared", + "estree-walker", + "magic-string", + "postcss", + "source-map-js" + ] + }, + "@vue/compiler-ssr@3.5.23": { + "integrity": "sha512-Hld2xphbMjXs9Q9WKxPf2EqmE+Rq/FEDnK/wUBtmYq74HCV4XDdSCheAaB823OQXIIFGq9ig/RbAZkF9s4U0Ow==", + "dependencies": [ + "@vue/compiler-dom", + "@vue/shared" + ] + }, + "@vue/devtools-api@7.7.7": { + "integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==", + "dependencies": [ + "@vue/devtools-kit" + ] + }, + "@vue/devtools-kit@7.7.7": { + "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", + "dependencies": [ + "@vue/devtools-shared", + "birpc", + "hookable", + "mitt", + "perfect-debounce", + "speakingurl", + "superjson" + ] + }, + "@vue/devtools-shared@7.7.7": { + "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", + "dependencies": [ + "rfdc" + ] + }, + "@vue/reactivity@3.5.23": { + "integrity": "sha512-ji5w0qvrPyBmBx5Ldv4QGNsw0phgRreEvjt0iUf1lei2Sm8//9ZAi78uM2ZjsT5gk0YZilLuoRCIMvtuZlHMJw==", + "dependencies": [ + "@vue/shared" + ] + }, + "@vue/runtime-core@3.5.23": { + "integrity": "sha512-LMB0S6/G7mFJcpQeQaZrbsthFbWrIX8FVTzu5x9U3Ec8YW5MY1CGAnBBHNj+TPOBu3pIbtPpjrXtcaN04X+aBw==", + "dependencies": [ + "@vue/reactivity", + "@vue/shared" + ] + }, + "@vue/runtime-dom@3.5.23": { + "integrity": "sha512-r/PYc8W9THzEL0UExpTkV+d31zO+Jid/RMZIDG6aS/NekOEUHuCJkJgftySWZw7JTJO/+q9Kxkg8p+i7Q7Q+ew==", + "dependencies": [ + "@vue/reactivity", + "@vue/runtime-core", + "@vue/shared", + "csstype" + ] + }, + "@vue/server-renderer@3.5.23_vue@3.5.23": { + "integrity": "sha512-NiWZsNCsXA20/VufcrW5u+Trt/PyFlpMmxaB2KERYM8eZgUoKUjXxJQb9ypq+LZ0Sp3XHJGNBR8DkhRnkKAMUw==", + "dependencies": [ + "@vue/compiler-ssr", + "@vue/shared", + "vue" + ] + }, + "@vue/shared@3.5.23": { + "integrity": "sha512-0YZ1DYuC5o/YJPf6pFdt2KYxVGDxkDbH/1NYJnVJWUkzr8ituBEmFVQRNX2gCaAsFEjEDnLkWpgqlZA7htgS/g==" + }, + "birpc@2.7.0": { + "integrity": "sha512-tub/wFGH49vNCm0xraykcY3TcRgX/3JsALYq/Lwrtti+bTyFHkCUAWF5wgYoie8P41wYwig2mIKiqoocr1EkEQ==" + }, + "copy-anything@4.0.5": { + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dependencies": [ + "is-what" + ] + }, + "csstype@3.1.3": { + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "earcut@3.0.2": { + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==" + }, + "entities@4.5.0": { + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "esbuild@0.25.12": { + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "optionalDependencies": [ + "@esbuild/aix-ppc64", + "@esbuild/android-arm", + "@esbuild/android-arm64", + "@esbuild/android-x64", + "@esbuild/darwin-arm64", + "@esbuild/darwin-x64", + "@esbuild/freebsd-arm64", + "@esbuild/freebsd-x64", + "@esbuild/linux-arm", + "@esbuild/linux-arm64", + "@esbuild/linux-ia32", + "@esbuild/linux-loong64", + "@esbuild/linux-mips64el", + "@esbuild/linux-ppc64", + "@esbuild/linux-riscv64", + "@esbuild/linux-s390x", + "@esbuild/linux-x64", + "@esbuild/netbsd-arm64", + "@esbuild/netbsd-x64", + "@esbuild/openbsd-arm64", + "@esbuild/openbsd-x64", + "@esbuild/openharmony-arm64", + "@esbuild/sunos-x64", + "@esbuild/win32-arm64", + "@esbuild/win32-ia32", + "@esbuild/win32-x64" + ], + "scripts": true, + "bin": true + }, + "estree-walker@2.0.2": { + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "fdir@6.5.0_picomatch@4.0.3": { + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dependencies": [ + "picomatch" + ], + "optionalPeers": [ + "picomatch" + ] + }, + "fsevents@2.3.3": { + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "os": ["darwin"], + "scripts": true + }, + "geojson-vt@4.0.2": { + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==" + }, + "get-stream@6.0.1": { + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "gl-matrix@3.4.4": { + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==" + }, + "hookable@5.5.3": { + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" + }, + "is-what@5.5.0": { + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==" + }, + "json-stringify-pretty-compact@4.0.0": { + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==" + }, + "kdbush@4.0.2": { + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" + }, + "magic-string@0.30.21": { + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dependencies": [ + "@jridgewell/sourcemap-codec" + ] + }, + "maplibre-gl@5.16.0": { + "integrity": "sha512-/VDY89nr4jgLJyzmhy325cG6VUI02WkZ/UfVuDbG/piXzo6ODnM+omDFIwWY8tsEsBG26DNDmNMn3Y2ikHsBiA==", + "dependencies": [ + "@mapbox/geojson-rewind", + "@mapbox/jsonlint-lines-primitives", + "@mapbox/point-geometry", + "@mapbox/tiny-sdf", + "@mapbox/unitbezier", + "@mapbox/vector-tile", + "@mapbox/whoots-js", + "@maplibre/maplibre-gl-style-spec", + "@maplibre/mlt", + "@maplibre/vt-pbf", + "@types/geojson", + "@types/geojson-vt", + "@types/supercluster", + "earcut", + "geojson-vt", + "gl-matrix", + "kdbush", + "murmurhash-js", + "pbf", + "potpack", + "quickselect", + "supercluster", + "tinyqueue" + ] + }, + "minimist@1.2.8": { + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mitt@3.0.1": { + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + }, + "murmurhash-js@1.0.0": { + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" + }, + "nanoid@3.3.11": { + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "bin": true + }, + "pbf@4.0.1": { + "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", + "dependencies": [ + "resolve-protobuf-schema" + ], + "bin": true + }, + "perfect-debounce@1.0.0": { + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" + }, + "picocolors@1.1.1": { + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "picomatch@4.0.3": { + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==" + }, + "pinia@3.0.4_vue@3.5.23": { + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "dependencies": [ + "@vue/devtools-api", + "vue" + ] + }, + "postcss@8.5.6": { + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dependencies": [ + "nanoid", + "picocolors", + "source-map-js" + ] + }, + "potpack@2.1.0": { + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==" + }, + "protocol-buffers-schema@3.6.0": { + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + }, + "quickselect@3.0.0": { + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" + }, + "resolve-protobuf-schema@2.1.0": { + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "dependencies": [ + "protocol-buffers-schema" + ] + }, + "rfdc@1.4.1": { + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + }, + "rollup@4.52.5": { + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dependencies": [ + "@types/estree" + ], + "optionalDependencies": [ + "@rollup/rollup-android-arm-eabi", + "@rollup/rollup-android-arm64", + "@rollup/rollup-darwin-arm64", + "@rollup/rollup-darwin-x64", + "@rollup/rollup-freebsd-arm64", + "@rollup/rollup-freebsd-x64", + "@rollup/rollup-linux-arm-gnueabihf", + "@rollup/rollup-linux-arm-musleabihf", + "@rollup/rollup-linux-arm64-gnu", + "@rollup/rollup-linux-arm64-musl", + "@rollup/rollup-linux-loong64-gnu", + "@rollup/rollup-linux-ppc64-gnu", + "@rollup/rollup-linux-riscv64-gnu", + "@rollup/rollup-linux-riscv64-musl", + "@rollup/rollup-linux-s390x-gnu", + "@rollup/rollup-linux-x64-gnu", + "@rollup/rollup-linux-x64-musl", + "@rollup/rollup-openharmony-arm64", + "@rollup/rollup-win32-arm64-msvc", + "@rollup/rollup-win32-ia32-msvc", + "@rollup/rollup-win32-x64-gnu", + "@rollup/rollup-win32-x64-msvc", + "fsevents" + ], + "bin": true + }, + "rw@1.3.3": { + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "source-map-js@1.2.1": { + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "speakingurl@14.0.1": { + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==" + }, + "supercluster@8.0.1": { + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "dependencies": [ + "kdbush" + ] + }, + "superjson@2.2.5": { + "integrity": "sha512-zWPTX96LVsA/eVYnqOM2+ofcdPqdS1dAF1LN4TS2/MWuUpfitd9ctTa87wt4xrYnZnkLtS69xpBdSxVBP5Rm6w==", + "dependencies": [ + "copy-anything" + ] + }, + "three@0.182.0": { + "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==" + }, + "tinyglobby@0.2.15_picomatch@4.0.3": { + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dependencies": [ + "fdir", + "picomatch" + ] + }, + "tinyqueue@3.0.0": { + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" + }, + "vite@7.2.1_picomatch@4.0.3": { + "integrity": "sha512-qTl3VF7BvOupTR85Zc561sPEgxyUSNSvTQ9fit7DEMP7yPgvvIGm5Zfa1dOM+kOwWGNviK9uFM9ra77+OjK7lQ==", + "dependencies": [ + "esbuild", + "fdir", + "picomatch", + "postcss", + "rollup", + "tinyglobby" + ], + "optionalDependencies": [ + "fsevents" + ], + "bin": true + }, + "vue@3.5.23": { + "integrity": "sha512-CfvZv/vI52xUhumUvHtD6iFIS78nGWfX4IJnHfBGhpqMI0CwDq2YEngXOeaBFMRmiArcqczuVrLxurvesTYT9w==", + "dependencies": [ + "@vue/compiler-dom", + "@vue/compiler-sfc", + "@vue/runtime-dom", + "@vue/server-renderer", + "@vue/shared" + ] + } + }, + "workspace": { + "dependencies": [ + "npm:@vitejs/plugin-vue@5", + "npm:maplibre-gl@^5.16.0", + "npm:pinia@^3.0.4", + "npm:three@0.182", + "npm:vite@^7.2.1", + "npm:vue@^3.5.23" + ] + } +} diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 0000000..654700c --- /dev/null +++ b/ui/index.html @@ -0,0 +1,12 @@ + + + + + + MoundHunters + + +
+ + + diff --git a/ui/public/tiles b/ui/public/tiles new file mode 120000 index 0000000..26e4c1e --- /dev/null +++ b/ui/public/tiles @@ -0,0 +1 @@ +/home/mark/projects/moundhunters/data/MOUND \ No newline at end of file diff --git a/ui/src/App.vue b/ui/src/App.vue new file mode 100644 index 0000000..f4467b2 --- /dev/null +++ b/ui/src/App.vue @@ -0,0 +1,395 @@ + + + + + \ No newline at end of file diff --git a/ui/src/main.js b/ui/src/main.js new file mode 100644 index 0000000..48ac44e --- /dev/null +++ b/ui/src/main.js @@ -0,0 +1,6 @@ +import { createApp } from 'vue' +import App from './App.vue' + + +const app = createApp(App) +app.mount('#app') \ No newline at end of file diff --git a/ui/vite.config.js b/ui/vite.config.js new file mode 100644 index 0000000..6cc235f --- /dev/null +++ b/ui/vite.config.js @@ -0,0 +1,55 @@ +import { defineConfig } from 'vite' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import vue from '@vitejs/plugin-vue' + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +export default defineConfig({ + plugins: [ + vue(), + ], + optimizeDeps: { + include: ['vue'] + }, + build: { + outDir: '../priv/static', + emptyOutDir: false, + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + output: { + entryFileNames: 'app.js', + chunkFileNames: 'chunks/[name].js', + assetFileNames: 'assets/[name].[ext]' + } + } + }, + resolve: { + alias: { + "@": fileURLToPath(new URL('./src', import.meta.url)), + "@stores": fileURLToPath(new URL('./src/stores', import.meta.url)), + }, + }, + server: { + proxy: { + '/socket': { + target: 'http://localhost:4000', + changeOrigin: true, + secure: false + }, + '/api': { + target: 'http://localhost:4000', + changeOrigin: true, + secure: false + }, + '/admin': { + target: 'http://localhost:4000', + changeOrigin: true, + secure: false + }, + } + } +}) +