Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
はてなCMSでFigmaを取り込むシステムに使われている技術
Search
NanimonoDemonai
November 29, 2025
160
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
はてなCMSでFigmaを取り込むシステムに使われている技術
Kyoto.js 24
NanimonoDemonai
November 29, 2025
More Decks by NanimonoDemonai
See All by NanimonoDemonai
LLMを「機能」として組み込む技術:「Figma to はてなCMS」におけるプロンプトエンジニアリングからAIエージェント構築にわたる精度向上の軌跡
nanimonodemonai
0
610
はてなCMSのアーキテクチャ; 巨大な既存システムと共存して最新技術を取り入れる
nanimonodemonai
0
850
ViteでCSSのバージョン違いを作る
nanimonodemonai
0
110
はてなブログのブログ表示に必要なJSを1/6にした話
nanimonodemonai
0
1k
はてなブログのESM化
nanimonodemonai
0
430
登壇資料.pdf
nanimonodemonai
0
450
はてなブログのフロントエンドに秩序はもたらされたのか
nanimonodemonai
3
6.2k
Featured
See All Featured
Un-Boring Meetings
codingconduct
0
420
Google's AI Overviews - The New Search
badams
0
1.6k
How to make the Groovebox
asonas
2
2.4k
Embracing the Ebb and Flow
colly
88
5.2k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
290
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
The agentic SEO stack - context over prompts
schlessera
0
940
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Navigating Team Friction
lara
192
16k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
Transcript
,ZPUPKT id: nanimono_demonai ͯͳCMSͰFigmaΛऔΓࠐΉγεςϜʹ ΘΕ͍ͯΔٕज़
ࣗݾհɾΠϯτϩ AIΤʔδΣϯτͷߏங FigmaϓϥάΠϯͷߏங Server-Sent Events 2
ࣗݾհɾΠϯτϩ 3
ࣗݾհ • id: nanimono_demonai • @NanimonoDaemon • ͯͳϒϩάɺͯͳCMSͷ։ൃͱɺλεΫཧΛߦ͏ • େֶͰػցֶशʢػց༁ʣΛݚڀ͍ͯͨ͠
4
ͯͳCMSͱ 5 ·Ί͖ͪ͠ ϩΰϖϯϩʔζͷࡾ֯ܗ https://www.hatena.ne.jp/cms/ ײతͳૢ࡞ੑ ڧݻͳηΩϡϦςΟ ॊೈͳίϯςϯπཧ ࠷৽ػೳΛ͍ͭͰ •
ͯͳͷ๏ਓ͚αʔϏε
ͯͳCMSͷΞʔΩςΫνϟ 6 ·Ί͖ͪ͠ https://speakerdeck.com/nanimonodemonai/hatenacmsnoakitekutiya-ju-da-naji- cun-sisutemutogong-cun-sitezui-xin-ji-shu-woqu-riru-reru Next.jsͷTypeScriptΞϓϦέʔγϣϯ ࠷ۙ/FYUʹͯ͠5VSCPQBDLʹ͠·ͨ͠ɻ݁ՌϏϧυߴԽ͞Εͨͷ·ͨผͷʜ
Figma to ͯͳCMSͱ 7
• ʮσβΠϯʯͱʮ࣮ʯͷஅΛຒΊΔαʔϏεΛ࡞Γ͍ͨ • FigmaͷσβΠϯσʔλΛͯͳCMSʹࣗવͳίʔυͱͯ͠ө͍ͨ͠ • ͔͠͠ɺFigmaͷσʔλMarkdownͷΑ͏ʹHTMLͱશવରԠ͍ͯ͠ͳ͍ • ๏ਓ͚ͷαʔϏεͱͯ͠࡞ΔʢͳͷͰɺݸਓͰ͑·ͤΜ…ʣ ՝: FigmaͰ࡞ͬͨσʔλΛऔΓࠐΊΔFigmaϓϥάΠϯΛ࡞Γ͍ͨ
8 ·Ί͖ͪ͠ ࠓ'JHNB3FBDUʹ͢ΔαʔϏεग़͍ͯ͠·͢ AIʹΑΔΞϓϦέʔγϣϯ࡞͕ख़͍ͯ͠Δੈͷத͔ͩΒ AIΛ׆༻ͯ͠ΞϓϦέʔγϣϯΛ࡞Ζ͏
࣌ͷઌߦࣄྫௐࠪ • FigmaΛHTMLʹ͢ΔͨΊͷɺϧʔϧϕʔεͷΦʔϓϯιʔε͕͋Δ • Coding AgentͰFigma৯ΘͤΕɺHTMLͱCSSΛॻ͍ͯ͘ΕΔ • Gemini 2.5 Proʹ৯ΘͤΕɺHTMLͱCSSΛԠͯ͘͠ΕΔ
• ௐࠪͷՌͱͯ͠ϓϩϯϓτҰൃͰม͢ΔPOC࡞ͬͯɺօͷධՁ্ʑ 9 ઌߦࣄྫΛ͋ͨͬͯΈΔͱ… ͔͠͠ɺAIʹ͓ͤͰ͏·͍͔͘ͳ͔ͬͨ
AIΤʔδΣϯτͷߏங 10
Figma࿈ܞͰ • ҰճͷLLMݺͼग़͠Ͱɺͯ͢ͷHTMLΛग़ྗ͢Δ͜ͱ͕Ͱ͖ͳ͍ • ग़ྗτʔΫϯͷݶք͕͋ΔͨΊ • ͔͠͠ɺग़ྗτʔΫϯΛ૿ͨ͢Ίʹɺ࠶ؼతʹೖྗͤͨ͞ͷΛग़ྗͤ͞Δ ΈͰ࣭͕ྼԽͯ͠͠·͏ 11 ᘳͳࢦࣔจʢਆϓϩϯϓτʣʹݶք͕͋ͬͨ
ͦ͜ͰɺAIΤʔδΣϯτతΞϓϩʔνͷ࣮ʹΓସ͑Δ͜ͱʹ
AIΤʔδΣϯτΛ࡞ΔͨΊʹ • ٻΊΔ࣭ͷग़ྗ͕ಘΒΕΔ·Ͱɺग़ྗʹԠͯ͡৽ͨͳਪΛߦΘ͍ͤͨ • ͜Ε·Ͱͷग़ྗΛอଘ͍ͨ͠ • ͜ΕΒΛAIαʔϏεͷΠϯλʔϑΣʔεʹґଘͤͣʹ࡞Γ͍ͨ 12 ʮAIʹ͓ͤʯͰͲΜͲΜखʹෛ͑ͳ͍࣮ͷෳࡶ͕͞ొͯ͘͠Δ ͜ΕΒΛղܾ͢ΔϥΠϒϥϦͱͯ͠զʑLangChainͱLangGraphΛ࠾༻
Agentic Work fl owΛࢧ͑Δٕज़ 13 Agent Framework Agent Runtime Agent
Harness • LangChain.js :͞·͟·ͳAIαʔϏεΛ౷Ұͨ͠ΠϯλʔϑΣʔεͰѻ͑Δ • αʔϏεΛநԽ͢ΔͨΊͷϨΠϠʔ https://blog.langchain.com/agent-frameworks-runtimes-and-harnesses-oh-my/ • LangGraph.js: ΤʔδΣϯτͷ෦ঢ়ଶΛཧ͢Δ • ReactͰ͍͏ͱ͜ΖͷReduxͳͲͷεςʔτཧϥΠϒϥϦͷงғؾ • Deep Agents: جຊతͳΤʔδΣϯτΛ࡞ΔͨΊͷϑϨʔϜϫʔΫ
Figma࿈ܞ࠷ऴతʹͲ͏࡞ΒΕ͍ͯΔΜ͚ͩͬʁ • LangGraph.jsΛ༻͍ͨAgentic Work fl ow • LangChain.jsͰݺͼग़͍ͯ͠ΔAIαʔϏε Vertex AI
(Gemini 2.5 pro) • ΞʔΩςΫνϟRe fl ectionͱݺΕΔ ͷͰɺAIʹࣗͷग़ྗΛఆͤ͞ɺظ͢ Δग़ྗΛಘΒΕΔ·Ͱग़ྗΛॻ͖ͤ͞Δ Έ 14 ·Ί͖ͪ͠ ਪʹ͕͔͔࣌ؒΔ͔Βɺ"QQͷ֎Ͱಈ͔͍ͯ͠·͢ "NB[PO424ͰΩϡʔΠϯά͍ͯ͠Δ
Figma Pluginͷߏங 15
Figma Pluginͷ֎؍ 16 https://developers. fi gma.com/docs/plugins/how-plugins-run/ FigmaͷηΩϡϦςΟʹΑΓɺΠϯλʔωοτͷΞΫηε͕ݫ͍͠
Figma PluginͰͷೝূ 17 ࢀর: https://developers. fi gma.com/docs/plugins/how-plugins-run/ ͜ͷՕॴΛ Ͳ͏ϥΫʹ࡞Ζ͏͔ʁ
Server-Sent Events 18
ͳͥServer-Sent Events͕ඞཁ͔ʁ • AIʹΑΔਪɺΞϓϦέʔγϣϯͷ֎Ͱ͕͔͔࣌ؒΔඇಉظॲཧ • มͷਐḿ݁ՌΛϦΞϧλΠϜʹΫϥΠΞϯτ௨͢Δͱྑ͍ • FigmaϓϥάΠϯͷೝূɺΞϓϦέʔγϣϯͷ֎Ͱ͕͔͔࣌ؒΔඇಉظॲཧ • ͍ͭऴΘΔ͔Θ͔Βͳ͍ϢʔβʔͷॲཧΛͨͳ͍ͱ͍͚ͳ͍
19 Ͳ͔͜ʹɺ؆୯ʹ࣮Ͱ͖Δ௨ٕज़͕ͳ͍͔ͳ͋ʁ
Server-Sent Events 20 https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events • αʔόʔ͔ΒΫϥΠΞϯτʹҰํʹσʔλΛૹ৴͢Δ͜ͱʹಛ Խٕͨ͠ज़ • ํʹ͚ͨ͠ΕWebSocket͕͍͍ͩΖ͏ •
HTTPϓϩτίϧͰಈ࡞ • γϯϓϧ͔ͭɺ࣮͕༰қ • ΫϥΠΞϯτ͕Web APIͷEventSource ʹؚ·Ε͓ͯΓར༻͕༰ қ
Server-Sent Eventsͷ࣮ 21 async function * readPolling(readKey: string) { const
encoder = new TextEncoder(); while (true) { const code = await getCodeForReadKey(readKey); if (code.type = = = 'pending') { yield encoder.encode('event: pending\ndata: pending\n\n'); await sleep(1000); continue; } if (code.type = = = 'expired') { yield encoder.encode('event: expired\ndata: expired\n\n'); return; } if (code.type = = = 'denied') { yield encoder.encode('event: denied\ndata: denied\n\n'); return; } if (code.type = = = 'success') { yield encoder.encode(`event: success\ndata: ${code.code}\n\n`); return; } return; } } • ͜Μͳײ͡ͷδΣωϨʔλ ؔΛ༰қ͢Δ
Server-Sent Events 22 export function GET(request: NextRequest) { const searchParams
= request.nextUrl.searchParams; const readKey = searchParams.get('readKey'); if (!readKey) { return new Response('bad request', { status: 400 }); } const iterator = readPolling(readKey); const stream = iteratorToStream(iterator); request.signal.onabort = async () = > { await clearReadKey(readKey); }; return new Response(stream, { headers: { 'Content-Type': 'text/event - stream', 'Cache-Control': 'no - cache, no - transform', 'Connection': 'keep - alive', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }, }); } function iteratorToStream(iterator: AsyncGenerator<Uint8Array>) { return new ReadableStream({ async pull(controller) { const { value, done } = await iterator.next(); if (done) { controller.close(); } else { controller.enqueue(value); } }, }); } • Next.jsͳΒɺ RouteϋϯυϥʹδΣω ϨʔλؔΛ ReadableStreamʹม͠ ͨͷΛͯ͠Ε
Figma to ͯͳCMSʹ͓͚ΔServer-Sent Eventsͷ۩ମతͳར༻γʔϯ • ೝূϑϩʔͰͷϙʔϦϯά • FigmaϓϥάΠϯ͔ΒͷOIDCೝূετϦʔϜʹ͓͍ͯɺreadKeyʹอଘ͞Εͨೝ ূίʔυͷঢ়ଶΛϙʔϦϯά͢Δͷʹར༻ •
ม݁ՌͷετϦʔϛϯά͍ͬͯͳ͍ͷͷ… • ͔͠͠ɺServer-Sent EventsAI͕ੜͨ͠ίʔυยΛϢʔβʔʹܧଓతʹૹ৴ ͠ϦΞϧλΠϜʹө͢Δ͜ͱʹΑ͘ΘΕΔٕज़ 23 Next.jsͰ؆୯ʹServer-Sent EventsΛ࡞Δํ๏͕ݟ͔ͭͬͨͷͰɺ ࠓޙ׆༻͍͖͍ͯͨ͠
·ͱΊ: ࠓճ͝հͨ͠ͷ • AIΤʔδΣϯτΛ࡞͢ΔͨΊͷٕज़ • Figma Pluginͷ࡞ʹ͓͚Δೝূܥϑϩʔෳࡶ • ৭ʑͳՕॴͰར༻ՄೳͳServer-Sent Eventsͷϓϩτίϧ֓ཁ
• ͦͯ͠Next.jsͰͷ࣮ํ๏ 24
ऴΘΓ 25