Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kartore: A Style Editor and Toolkit for MapLibre

Kartore: A Style Editor and Toolkit for MapLibre

Avatar for Taiyu Yoshizawa

Taiyu Yoshizawa

September 02, 2026

More Decks by Taiyu Yoshizawa

Other Decks in Programming

Transcript

  1. Who am I? Taiyu Yoshizawa (a.k.a. ɴᴇᴋᴏʏᴀsᴀɴ) Software Engineer @MIERUNE

    Inc. Co-founder & Software Engineer @ ReMotive LLC. GitHub: @NEKOYASAN Twitter: @Nekoya3_ Web: nekoyasan.me
  2. Edited one with Maputnik Edited one with MVT Styler Edited

    the JSON directly in VS Code or another editor Never edited one
  3. Filters or expressions can crash the app Git requires manual

    local saves and commits Colors and values cannot be shared across many layers Sprites and glyphs cannot be generated or edited It is not intuitive enough for newcomers
  4. Filters or expressions can crash the app Git requires manual

    local saves and commits Colors and values cannot be shared across many layers Sprites and glyphs cannot be generated or edited It is not intuitive enough for newcomers
  5. What can Kartore do today? Add or remove sources and

    edit layer styles Inspect source data Preview the style Generate sprites from SVG icons Generate glyphs from font files Package all of the above into a single portable file Export style.json, sprite.json/PNG, and glyph PBF files from that package
  6. What can Kartore do today? Commit, push, and open pull

    requests through GitHub Review diffs side by side Track style changes in Git Reuse variables for colors, values, and interpolation Extend storage backends
  7. Key features Extend functionality through the adapter system Built-in GitHub

    integration Support version-history workflows Treat values inside a style as variables Give semantic names to colors and other values Build theme-like behavior with global-state Generate glyphs and sprites in the same workflow
  8. How is it built? Currently split into five components web

    file-adapter github-adapter spritore glyphore
  9. What each component does glyphore (github.com/kartore/glyphore) Creates MapLibre SDF glyph

    PBFs from TTF and OTF web stores source fonts; glyphore builds requested ranges on demand Extracts font metadata and Unicode ranges Available in Rust, WebAssembly, JavaScript, and CLI
  10. What each component does spritore (github.com/kartore/spritore) Generates MapLibre sprites from

    SVGs Performs basic optimization Rasterizes images; builds a PNG sprite sheet and JSON index Uses individual images through map.addImage while editing Available in Rust, WebAssembly, JavaScript, and CLI
  11. What each component does web (github.com/kartore/svelte) MapLibre Style Editor UI

    Map, inspector, and style editor Builds and restores Style JSON, split styles, and packs Creates, binds, and resolves variables Adapter extension API UI, storage, history, and project loading Stores SVGs and fonts; calls spritore/glyphore
  12. What each component does web (github.com/kartore/svelte) MapLibre Style Editor UI

    Map, inspector, and style editor Builds and restores Style JSON, split styles, and packs Creates, binds, and resolves variables Adapter extension API UI, storage, history, and project loading Stores SVGs and fonts; calls spritore/glyphore
  13. What is a split style? A Style JSON file split

    into separate files by layer Layer order is managed in a separate layers.json file Sources and other root-level style properties are stored in separate JSON files
  14. Why use split styles? Track changes within each layer more

    easily in Git Layer files are easier to track than large JSON arrays Separate files stay traceable when layers move Renamed layer IDs remain the main tradeoff
  15. What is an adapter? Separates the editor core from storage

    and services web provides shared editing UI, state, and API Each adapter owns its service connection and UI Storage, loading, history, and auth live in adapters Hosts register adapter UI, providers, and APIs One contract lets storage change without editing the core
  16. File adapter GitHub adapter The UI and Logic can be

    injected from the adapter side as needed.
  17. MenuSection / HeaderStatus / RailItem / Overlays Can be added

    as a Svelte component from the adapter side to a part of the UI
  18. There's more /[adapter-id]/[...path] Adapters can add SvelteKit pages and use

    page data and other framework features /api/[adapter-id]/[...path] API routes are exposed in the same way A Hono application is mounted internally through app.fetch Cloudflare bindings are available through ctx
  19. For example... We store styles in our own database
 →

    Build an adapter with your login and access logic We use GitLab or GHES instead of GitHub
 → Adapt the GitHub adapter to those APIs A feature is missing
 → Extend both the UI and logic with an adapter
  20. Variables Turn style values into variables Edit once; every reference

    updates For example: One road color shared across layers One interpolation shared across layers Switch all variable values by mode Assign each variable a value in every style mode For example: Dark and Light modes
  21. Key features Export a separate Style JSON for each mode

    Export a single JSON using `global-state`
  22. One Style JSON per mode 1 2 3 4 5

    6 7 8 9 10 11 12 13 14 { } "name": "JP Street Light", "layers": [ ... { "id": "water", "type": "fill", "layout": {}, "paint": { "fill-color": "#FF1FE7", } } ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 { } "name": "JP Street Dark", "layers": [ ... { "id": "water", "type": "fill", "layout": {}, "paint": { "fill-color": "#33002D", } } ]
  23. One Style JSON per mode 1 2 3 4 5

    6 7 8 9 10 11 12 13 14 { "name": "JP Street Light", "layers": [ ... { "id": "water", "type": "fill", "layout": {}, "paint": { "fill-color": "#FF1FE7", } } ] street-light.json } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "name": "JP Street Dark", "layers": [ ... { "id": "water", "type": "fill", "layout": {}, "paint": { "fill-color": "#33002D", } } ] street-dark.json }
  24. Export a single JSON using `global-state` 1 { 2 "name":

    "JP Street", 3 "layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#FF1FE7", 11 } 12 } 13 14 ] }
  25. Export a single JSON using `global-state` 1 { 2 "name":

    "JP Street", 3 "state": { 4 "mode": { 5 "default": "light" 6 } 7 }, 8 "layers": [ 9 ... 10 { 11 "id": "water", 12 "type": "fill", 13 ...
  26. Export a single JSON using `global-state` 1 "layers": [ 2

    { 3 "id": "water", 4 "type": "fill", 5 "paint": { 6 "fill-color": [ 7 "case", 8 ["==", ["global-state", "mode"], "dark"], 9 "#33002D", 10 "#FF1FE7", 11 ] 12 } 13 14 } ]
  27. Export a single JSON using `global-state` Condition If mode is

    dark: #33002D Otherwise: #FF1FE7 At runtime... map.setGlobalStateProperty('mode', 'dark');
 Only affected map content is updated
  28. Export a single JSON using `global-state` Condition If mode is

    dark: #33002D Otherwise: #FF1FE7 At runtime... map.setGlobalStateProperty('mode', 'dark');
 Only affected map content is updated But...
  29. What is a .kartore file? A custom format for carrying

    styles between environments Despite the name, it is just a ZIP archive It bundles split-style data, editing fonts, and source SVGs for sprites file-adapter creates the ZIP; web owns the shared folder structure
  30. How is it built? Currently split into five components web

    file-adapter github-adapter spritore glyphore
  31. What each component does glyphore (github.com/kartore/glyphore) Creates MapLibre SDF glyph

    PBFs from TTF and OTF web stores source fonts; glyphore builds requested ranges on demand Extracts font metadata and Unicode ranges Available in Rust, WebAssembly, JavaScript, and CLI
  32. What each component does spritore (github.com/kartore/spritore) Generates MapLibre sprites from

    SVGs Performs basic optimization Rasterizes images; builds a PNG sprite sheet and JSON index Uses individual images through map.addImage while editing Available in Rust, WebAssembly, JavaScript, and CLI
  33. Traditional workflow Prepare POI icons and fonts Generate and host

    glyph and sprite files Write the style Repeat steps 1 and 2 for missing icons or fonts Deploy everything together when finished
  34. The Kartore workflow Prepare POI icons and fonts Write the

    style Add missing icons and fonts as needed Export everything together when finished • Static icon-image values omit unused icons • Unused fonts are omitted from glyph exports
  35. Kartore × GitHub Load styles from GitHub Create a branch,

    edit, stage, and commit Review branch changes side by side Open a pull request after review Preview directly from GitHub (planned) Comment on a layer at a map location (planned)
  36. Why GitHub integration? GitHub becomes the single source of truth

    for styles Accidental rollbacks are minimized Resolve team conflicts with a visual comparison Track the history of value changes Commit messages tie changes to their intent and author
  37. What's next? Make adapters easy for anyone to build Deepen

    GitHub integration Offer a managed service with custom extensions Improve CJK font handling in MapLibre Improve the expression-editing experience UI i18n support Create a logo and icon
  38. Please share lots of feedback GitHub Issues / X /

    LinkedIn / and more All feedback is welcome!