Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kartore: Maplibre のための Style Editor とその Toolkit
Search
Taiyu Yoshizawa
September 02, 2026
Technology
26
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kartore: Maplibre のための Style Editor とその Toolkit
Taiyu Yoshizawa
September 02, 2026
More Decks by Taiyu Yoshizawa
See All by Taiyu Yoshizawa
The Present and Future of CJK Rendering in MapLibre
nekoya3
0
7
Kartore: A Style Editor and Toolkit for MapLibre
nekoya3
0
9
Flagship という素晴らしいもの / This awesome thing called Flagship
nekoya3
0
2
10分で完全に理解出来る Cloudflare Workers + HyperDrive / Cloudflare Workers + HyperDrive: You Might Understand It in Just 10 Minutes
nekoya3
0
12
WorkersでCMSを作ってみないか / Wanna build a CMS with Workers?
nekoya3
0
9
Cloudflare Realtime と Workers でつくるサーバーレス WebRTC
nekoya3
1
1.9k
北海道新型コロナウイルスまとめサイトでのいろいろなこと
nekoya3
0
470
Other Decks in Technology
See All in Technology
Genie Code ワークショップ 応用編 / Genie-Code-Workshop-advanced
databricksjapan
PRO
0
350
AI 駆動 Terraform 開発/SRE_BizReach_MIXI_2
visional_engineering_and_design
2
1.3k
データエンジニアの困りごとをDevinと一緒に解消する
10xinc
2
830
Bet AI Day 2026丨Agentは、「金融」という巨大産業の何を変えられるのか
layerx
PRO
0
820
AIで実装は速くなった。なのにプロダクトは速くならない。職能の壁を越えて価値のフローを設計する
nwiizo
6
7.2k
Benchmarking Vector Databases: pgvector vs. LanceDB
tsho
0
140
はじめてのDatabricks:技術者向けワークショップ / beginner-workshop
databricksjapan
PRO
0
200
JAWS-UG初心者支部#88わいわい初心塾(夏休みの宿題やったかGit編)
otsuki
0
140
Bet AI Day 2026丨How We Bet AI: AIとともに働く場をつくる
layerx
PRO
2
2.4k
多層防御と最⼩権限で実現する、安全なAIエージェント設計パターン
lycorptech_jp
PRO
0
200
Sony-DroidKaigi2026
sony
1
320
書籍『生成AIの安全性入門』の入門
wataoka
0
210
Featured
See All Featured
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
840
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
440
Raft: Consensus for Rubyists
vanstee
141
7.7k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
230
Into the Great Unknown - MozCon
thekraken
41
2.7k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Color Theory Basics | Prateek | Gurzu
gurzu
0
460
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
340
Darren the Foodie - Storyboard
khoart
PRO
3
3.9k
Transcript
Taiyu Yoshizawa Kartore: A Style Editor and Toolkit for MapLibre
Who are you? Taiyu Yoshizawa (a.k.a. ɴᴇᴋᴏʏᴀsᴀɴ) Software Engineer @MIERUNE
Inc. Co-founder & Software Engineer @ ReMotive LLC. GitHub: @NEKOYASAN Twitter: @Nekoya3_ Web: nekoyasan.me
MapLibreのスタイルを 編集したことはありますか?
Maputnik を使って編集したことがある MVT Styler を使って編集したことがある JSONを直で VSCode などを使って頑張って書いたことがある 書いたことない
Maputnik
Maputnikを触ったことがあったら こんな苦労はなかったでしょうか?
FilterやExpressionsの設定をしようとするとアプリケーション がクラッシュする Git管理しようとすると都度ファイルをSaveして、手動で手元で コミットする必要がある レイヤーが多いスタイルで色などを共通化したくてもできない SpriteとGlyphの生成や編集はできない 新しく始める人におすすめできるわかりやすさではない
これを開発者視点で 解決しようとしても...
PropTypesを用いた型チェックがされているReact Project Class Componentで書かれていて若干近寄りにくい 拡張しやすい仕組みが用意されてはいない メンテナンスがどれだけ行われるかが不透明
PropTypesを用いた型チェックがされているReact Project Class Componentで書かれていて若干近寄りにくい 拡張しやすい仕組みが用意されてはいない メンテナンスがどれだけ行われるかが不透明
PropTypesを用いた型チェックがされているReact Project Class Componentで書かれていて若干近寄りにくい 拡張しやすい仕組みが用意されてはいない メンテナンスがどれだけ行われるかが不透明
PropTypesを用いた型チェックがされているReact Project Class Componentで書かれていて若干近寄りにくい 拡張しやすい仕組みが用意されてはいない メンテナンスがどれだけ行われるかが不透明
PropTypesを用いた型チェックがされているReact Project Class Componentで書かれていて若干近寄りにくい 拡張しやすい仕組みが用意されてはいない メンテナンスがどれだけ行われるかが不透明
Thank you!!!
FilterやExpressionsの設定をしようとするとアプリケーション がクラッシュする Git管理しようとすると都度ファイルをSaveして、手動で手元で コミットする必要がある レイヤーが多いスタイルで色などを共通化したくてもできない SpriteとGlyphの生成や編集はできない 新しく始める人におすすめできるわかりやすさではない
スタイルを編集するための 一貫したツールキットが必要なのでは?
Kartore: A Style Editor and Toolkit for MapLibre Taiyu Yoshizawa
Kartore
現状なにができるのか?
現状なにができるの? ソースの追加・削除やレイヤのスタイルが編集できる ソースのデータをinspectできる スタイルをプレビューできる SVGのアイコンからSpriteが生成できる FontデータからGlyphが生成できる ↑を1ファイルにパックして持ち運ぶことができる ↑からstyle.jsonとsprite.json/png、glyphのpbfファイルを それぞれexportできる
現状なにができるの? GitHubと連携してCommit / Push / Pull Requestが出せる 差分をSide by Sideで確認できる
styleのGit上での変更を追跡することができる。 色や値、interporationを変数化して複数の場所から利用できる 保存先などを拡張できる
ちょっとデモ app.kartore.io
どんな特徴があるか
どんな特徴があるか adapter という機構でさまざまな拡張が行える GitHub 連携がある Version History のようなものも作れる Style内の値を変数として捉えられる 色などの値に対して名前をつけられる
Modeでライトモードとダークモードみたいなことができる Glyph / Spriteの生成まで一貫して行える
adapter という機構でさまざまな拡張が行える
またデモ app.kartore.io
どんな仕組みでできているか (現状)5つのコンポーネントに分けている web file-adapter github-adapter spritore glyphore
それぞれの責務 web (github.com/kartore/svelte) MapLibre Style Editor の UI 全般 map、inspector、style
editor など Style JSON / split style / project pack などの仮想ファ イル群の生成・復元 Style 内の値の変数化・バインド・解決 adapter の拡張 API UI、保存、履歴、プロジェクト読み込み 元 SVG・font の保管と、spritore / glyphore の利用
それぞれの責務 web (github.com/kartore/svelte) MapLibre Style Editor の UI 全般 map、inspector、style
editor など Style JSON / split style / project pack などの仮想ファ イル群の生成・復元 Style 内の値の変数化・バインド・解決 adapter の拡張 API UI、保存、履歴、プロジェクト読み込み 元 SVG・font の保管と、spritore / glyphore の利用
split style とは? style JSONをレイヤー単位でファイル分解したもの レイヤーの順番は別ファイルのlayers.jsonで管理される sourcesやstyle側のRootにある属性も別のjsonファイルで 管理される
なぜ split style ? これを行うことで、同一レイヤ内での変更をgit的に追跡しやす くする 大きなJSONのArrayの特定の行よりも単一ファイルの方が 追跡のコストが安い レイヤーが前後に足されたときに、JSONのArrayだと正し く追跡できないが、ファイルに落とし込めば追跡できる
レイヤーIDが変わったときの追跡コストが高いのが難点
それぞれの責務 file-adapter (github.com/kartore/file-adapter) File System Access API による Style の
open / read / write / save ファイル接続状態・未保存変更・保存 UI の管理 .kartore ファイルの import / export
それぞれの責務 file-adapter (github.com/kartore/file-adapter) File System Access API による Style の
open / read / write / save ファイル接続状態・未保存変更・保存 UI の管理 .kartore ファイルの import / export
.kartore ファイル とは? スタイルの持ち運びを楽にするために作った独自形式 とは言っているが、実態はただのzip split styleのスタイルデータと、編集時に必要なフォントファイ ルとspriteの元データのSVGをひとまとめにしてzipに固めたも の zip化などはfile-adapter側で実施するが、ファイル内のフォル
ダ構造はgithub-adapterなどでも使うため、web側の責務
それぞれの責務 github-adapter GitHub OAuth / GitHub App 経由の repository・ branch・file
操作 Style の読み込み・commit・branch 作成・conflict 検 知 commit history、diff、preview link、Pull Request、 webhook GitHub 連携用の UI と adapter 実装
adapterとは?
adapterとは? エディタ本体と、保存先・外部サービスを分離する拡張 web は共通の編集 UI・編集状態・Editor API を提供 各 adapter は外部サービスとの接続方法と、固有の
UI を 担当 保存、読み込み、履歴、認証などを adapter ごとに実装 host が adapter を登録すると、adapter の UI・ provider・API がエディタに組み込まれる 共通の契約を使うため、保存先を差し替えてもエディタ本体を変 更せずに利用できる
None
GitHub adapter
File adapter GitHub adapter
File adapter GitHub adapter 必要に応じてUIを adapter側から差し込める
MenuSection / HeaderStatus / RailItem / Overlays UIの一部に対してadapter側から Svelteコンポーネントとして追加できる
File adapter GitHub adapter ほかにも...
他にも /[adapter-id]/[...path] SvelteKitのPageがすべてAdapter側に公開されている page自体の追加やpageDataなどSvelteKitの機能を自由 に使える /api/[adapter-id]/[...path] API Routesも同様にAdapter側に公開されている こちらはHonoのアプリケーションを内部的にapp.fetchを 読み替えて渡している
CloudflareのBindingなどもctx経由で利用できる
他にも /[adapter-id]/[...path] SvelteKitのPageがすべてAdapter側に公開されている 差分確認ページなど page自体の追加やpageDataなどSvelteKitの機能を自由 に使える /api/[adapter-id]/[...path] API Routesも同様にAdapter側に公開されている こちらはHonoのアプリケーションを内部的にapp.fetchを
GitHub APIへのアクセスなど 読み替えて渡している CloudflareのBindingなどもctx経由で利用できる
なにが嬉しいのか?
自前でadapterを作って拡張できる
例えば... 自社でDBにスタイルデータを持っているのでそれを編集する用 途に使いたい → 自前でログインとかを実装したうえでアクセスできるように adapterを書けばUIは乗っかったまま書ける GitHubじゃなくてGitLab / GHESを使ってる →
GitHub Adapterを参考にAPIを使えるようにさえすればそ れらでも使える 機能的に足りないものがある → UIにもロジックにも介入できるので容易に足せる
Style内の値を変数として捉えられる
見てもらったほうが早いのでデモ app.kartore.io
Variables Style内の値を変数化できる機能 一つの値を変えると同じvariableを使ってる値も変わる 例えば 道路が複数レイヤーに分かれているけど色が一緒 interpolateで複数のレイヤーで同じ変化を与えるケース VariableをModeによって一括で差し替える機能 Styleに対して複数のModeを作成し、同じVariable内で Modeごとに色を決めることができる 例えば:Dark
Mode と Light Modeを作るとき
None
None
None
2パターンの出力が行える
どんな特徴があるか 各モードのStyle JSONをそれぞれ出力する `global-state` を使い1つのJSONで出力する
各モードのStyle JSONをそれぞれ出力する 1 { 2 "name": "JP Street Light", 3
"layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#FF1FE7", 11 } 12 } 13 ] 14 }
各モードのStyle JSONをそれぞれ出力する 1 { 2 "name": "JP Street Dark", 3
"layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#33002D", 11 } 12 } 13 ] 14 }
各モードのStyle JSONをそれぞれ出力する 1 { 2 "name": "JP Street Light", 3
"layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#FF1FE7", 11 } 12 } 13 ] 14 } 1 { 2 "name": "JP Street Dark", 3 "layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#33002D", 11 } 12 } 13 ] 14 }
各モードのStyle JSONをそれぞれ出力する 1 { 2 "name": "JP Street Light", 3
"layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#FF1FE7", 11 } 12 } 13 ] 14 } street-light.json 1 { 2 "name": "JP Street Dark", 3 "layers": [ 4 ... 5 { 6 "id": "water", 7 "type": "fill", 8 "layout": {}, 9 "paint": { 10 "fill-color": "#33002D", 11 } 12 } 13 ] 14 } street-dark.json
`global-state` を使い1つのJSONで出力する 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 }
`global-state` を使い1つのJSONで出力する 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 ...
1 2 3 4 5 6 7 8 9 10
11 12 13 14 `global-state` を使い1つのJSONで出力する "layers": [ { "id": "water", "type": "fill", "paint": { "fill-color": [ "case", ["==", ["global-state", "mode"], "dark"], "#33002D", "#FF1FE7", ] } } ]
1 2 3 4 5 6 7 8 9 10
11 12 13 14 `global-state` を使い1つのJSONで出力する "layers": [ { "id": "water", "type": "fill", "paint": { "fill-color": [ "case", ["==", ["global-state", "mode"], "dark"], "#33002D", "#FF1FE7", ] } } ]
`global-state` を使い1つのJSONで出力する 条件 modeがdarkなら、#33002D に modeがそれ以外なら、#FF1FE7 になる Runtime側からは... map.setGlobalStateProperty(‘mode’, ‘dark’);
のように設定すると、関係のある部分だけが差分更新される
`global-state` を使い1つのJSONで出力する 条件 modeがdarkなら、#33002D に modeがそれ以外なら、#FF1FE7 になる Runtime側からは... map.setGlobalStateProperty(‘mode’, ‘dark’);
のように設定すると、関係のある部分だけが差分更新される ただ...
global-state is not supported yet on Native
Native support in-progress...
この機能によって、 複数モードあるスタイル管理が楽になる
Glyph / Spriteの生成まで一貫して行える
.kartore ファイル とは? スタイルの持ち運びを楽にするために作った独自形式 とは言っているが、実態はただのzip split styleのスタイルデータと、編集時に必要なフォントファイ ルとspriteの元データのSVGをひとまとめにしてzipに固めたも の zip化などはfile-adapter側で実施するが、ファイル内のフォル
ダ構造はgithub-adapterなどでも使うため、web側の責務
スタイルに追加されたSVGとFontファイルは 必ずProjectに紐付けて保存される
どんな仕組みでできているか (現状)5つのコンポーネントに分けている web file-adapter github-adapter spritore glyphore
それぞれの責務 glyphore (github.com/kartore/glyphore) OTF / WOFF / TTF から MapLibre
用 glyph SDF PBF を生成 web が元 font を保管し、MapLibre から要求された range をオンデマンドで生成する font metadata と対応 Unicode range の抽出 Rust / WebAssembly / JavaScript / CLI から利用可能
それぞれの責務 spritore (github.com/kartore/spritore) SVG から MapLibre 用 sprite を生成 ある程度の軽量化も合わせて実施する
個別画像の rasterize、PNG sprite sheet、JSON index の生成 個別画像はスタイル作成中に map.addImage 経由で利 用される Rust / WebAssembly / JavaScript / CLI から利用可能
見てもらったほうが早いのでデモ app.kartore.io
None
None
旧来のワークフロー POIに使うアイコンやフォントを用意する Glyph と Sprite ファイルを生成して配置する スタイルを書く 足りないアイコンなどがあれば1,2を繰り返す 完成したらまとめてデプロイする
Kartoreのワークフロー POIに使うアイコンやフォントを用意する スタイルを書く 足りないアイコンやフォントは都度追加する 完成したらまとめて出力する `icon-image`などにExpressionを使っていない場合は、使 われていないアイコンは除外される `text-font`についても同様にGlyphから除外される
これがすべてGitHubとつながる
None
None
None
None
None
None
None
None
Kartore × GitHub GitHubからスタイルをロードできる Branchを切って変更を加え、Add / Commitできる Branch間の変更をSide-by-Sideで確認できる 確認した上でPull Request
を出せる GitHubからもプレビューできる (feature) 場所を指定した状態で対応するレイヤにレビューコメントをつけ られる (feature)
これによってなにが起きるか
Why GitHub integration? GitHub上のスタイルがSSoTになる 先祖返りを極力防げる 複数人でのコンフリクト解消がビジュアルで確認しながら行える 値の変更の履歴などが追跡できる 値の変更とコミットメッセージが完全に紐づくため、あとか ら変更意図・変更者が追いやすい
None
次はなにをするか
次はなにをするか Adapterをもっと容易に誰でも書けるように GitHub連携の強化 Managedな方向での独自拡張したサービス提供 MapLibre上のCJKフォントの扱いの改善 Expressionの編集体験の向上 Logo / Iconの作成
Kartore触ってみてね
そして
たくさんフィードバック をください GitHub Issue / Twitter / Linkedin / andmore...
everything welcome!
Thank you!