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
もう一歩進めたい OG画像の動的生成
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
mottox2
January 19, 2024
Programming
3k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
もう一歩進めたい OG画像の動的生成
mottox2
January 19, 2024
More Decks by mottox2
See All by mottox2
つくり方を変えていく | change-how-we-build
mottox2
2
1.5k
なぜコピペで使うコンポーネント集を利用するのか?
mottox2
8
7.6k
UIコンポーネントライブラリをうまく使うためにできること / components-with-designer
mottox2
7
4.1k
Figma Plugin公開までの壁を乗り越える
mottox2
3
4.2k
Puppeteerでつくる画像と動画 / images and videos made with puppeteer
mottox2
0
800
手触りのよいウェブを考える / better-mobile-web
mottox2
3
2.1k
組織と権限とSlack App / slack-app-with-roles
mottox2
1
740
SSRを避けるためにやっていること / ssr-alternative
mottox2
9
3.3k
JSXでつくる宣言的UIなプレゼンテーション / jsx-presentation
mottox2
7
34k
Other Decks in Programming
See All in Programming
なぜCTOを降りてFDEを選んだのか?〜なぜプロダクト企業がFDEで顧客の現場に踏み込むのか〜
gonta
1
190
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
490
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
330
setup-vp GitLab対応の裏側
naokihaba
0
160
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
Simple Storage Service(S3) is not simple
iwatsukayura
0
260
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
1
250
dotNET_vulnclicker_intro.pdf
deka_morita
0
140
気持ちぃ〜角丸 Squircle
ryu1013
0
280
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
1
2.3k
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
480
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
380
Featured
See All Featured
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
270
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
800
Testing 201, or: Great Expectations
jmmastey
46
8.3k
BBQ
matthewcrist
90
10k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
37k
Utilizing Notion as your number one productivity tool
mfonobong
4
620
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
320
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
540
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
560
Transcript
#burikaigi_m もう一歩進めたい OG画像の動的生成 BuriKaigi 2024 @mottox2
#burikaigi_m @mottox2 UIデザインとウェブフロントエンド
#burikaigi_m
#burikaigi_m
#burikaigi_m OG画像 E サイトの情報を伝えるためのOpen Graphというプロトコ P E その中の画像をOG画像と呼んでいh E 特にXではtitleやdescriptionより画像の主張が強いの
で、 各サイトやサービスが工夫を凝らしている
#burikaigi_m @vercel/ogとは?
#burikaigi_m @vercel/og ( JSXからsvgを生成するsatoriとsvgからpngが画像に変 換するresvgをVercel上でまとめて使えるようにしたも) ( Next.jsに組み込まれていて簡単に利用できる JSX satori resvg
SVG PNG
#burikaigi_m 例えば < {{ height: , width: , display: ,
flexDirection: , alignItems: , justifyContent: , backgroundColor: , fontSize: , fontWeight: , }} > < {{ margin: }} > < ></ > </ > < {{ marginTop: }}>Hello, World</ > </ > div svg path path svg div div div style width viewBox fill style d style = = = = = = = '100%' '100%' 'flex' 'column' 'center' 'center' '#fff' "75" "0 0 75 65" "#000" '0 75px' "M37.59.25l36.95 64H.64l36.95-64z" 32 600 40
#burikaigi_m 例えば < < > < /> </ > <
/> < > < /> </ > < > < /> </ > < < > < /> </ > < > < /> </ > svg mask rect mask rect rect mask rect mask image mask rect mask mask rect mask width height viewBox xmlns id x y width height fill x y width height fill id x y width height id x y width height fill x y width height href preserveAspectRatio clip-path mas id x y width height fill id x y width height fill = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = "800" "400" "0 0 800 400" "http://w "satori_om-id" "0" "0" "800" "400" "#fff" "0" "0" "800" "400" "#fff" "satori_cp-id-0" "363" "128" "75" "65" "satori_om-id-0" "363" "128" "75" "65" "#fff" "363" "128" "75" "65" "data:image/svg+xml;utf8,%3Csvg fill=%22%23000%22 xmlns=% "none" "url(#satori_cp-id-0)" "satori_om-id-0-0" "363" "128" "0" "65" "#fff" "satori_om-id-1" "304" "233" "193" "39" "#fff" clipPath clipPath
#burikaigi_m 例えば
#burikaigi_m @vercel/ogの嬉しさ ・ しんどさ 世の中の画像生成手法は座標を考えながら使う必要が あるが@vercel/ogではほとんど考えなく て良s 一方、
SatoriはHTMLのサブセッ トであり、 結構できなこと が多い
#burikaigi_m Playground https://satori-playground.vercel.app
#burikaigi_m サポート状況の確認 https://github.com/vercel/satori
#burikaigi_m 無事画像が作れるようになった ただ、 画像を作るだけではつまらない 自動作成された画像感を減らしたい
#burikaigi_m 自動作成されてる感はどこから来るのか? デザイン段階で決まってC 9 画像が浮いていC 9 フォントがデフォルト、 文字詰めが適b 9 Webっぽいグリッドを感じる
#burikaigi_m 標準で使われているフォントを使うと、 ダサさがある d 標準フォントでは太字指定が無視され@ d「」 、 。 などの役物の空きが気になる
#burikaigi_m デフォルト(Roboto) YakuHanJP
#burikaigi_m 標準で使われているフォントを使うと、 ダサさがある おすすめは qracさんが作られている YakuHanJP MergedのSemiboldかBolc Noto
Sans JPに対して、 半角サイズの役物 (句読点と 鉤括弧等の文字) を混ぜたフォント
#burikaigi_m 文字づめがされていない v 文字詰めをやるCSS `font-feature-settings: ‘palt’` はsatoriがサポートしていないため動かないi v → 場合によって代わりに
`letter-spacing: -0.02em` で全体的に詰めておくのもあり こんにちは世界 こんにちは世界 ツメなし ツメあり
#burikaigi_m 画像の使い方 そのまま使うとブログのアイキャッチ感があふれ` B 特定の形にトリミングしてみ` B 上からグラデーションの座布団を引G B ぼかしてみる
#burikaigi_m 視覚調整 Vercel 正しい位置に配置すると目の錯覚で小さく見える 世の中のロゴやフォントにはこの調整が入っている
#burikaigi_m 視覚調整の対応 R ウェブでは保守性のためスキップすることが多3 R 画像を作るならやるべ$ R マイナス側のマージンをつければOK
#burikaigi_m
#burikaigi_m 大切なこと R 何ができて、 何ができないかを知っておくこと ・ 伝えるこT R Web技術で作れることと、 Webのように作ることを混同
しない方がよ1 R レスポンシブとか考えなく てよく て、 特定のサイズに特化し たスタイリングを行えばよい
#burikaigi_m もう一歩、 プログラムで作る意味を見出したい
#burikaigi_m 何ができそうか? S ランダムに背景を選択すF S SVGを利用した動的なビジュアルを作F S 画像の色を考慮したビジュアルを作る
#burikaigi_m KODANSHAtech コーポレートブログの例
#burikaigi_m ランダムな背景を用意する S 真っ先に思いつくであろう活用U S ランダムに背景画像を切り替える実 S 完全ランダムにしてしまうと、 毎回変わってしまうので、 URLに対して一意にするための実装をするとよw
S シードを設定できるランダム関数の実装
#burikaigi_m class constructor = % if <= += return =
* % return - / let = new { ( ) { .seed seed ; ( .seed ) .seed ; } () { .seed .seed ; } () { ( . () ) ; } } rng ( ); console. (rng. ()); SeededRandom next nextFloat next SeededRandom log nextFloat seed this 2147483647 this 0 this 2147483646 this this 16807 2147483647 this 1 2147483646 12345 // 0から1の範囲で乱数を返す // 使用例 // シード値を設定 // 常に同じシード値で同じ乱数列を生成 generated by ChatGPT 同じURLでは同じ乱数が生成されるようにする
#burikaigi_m SVGを利用した動的なビジュアルを作る E vercel/ogはpngを生成する中間状態にSVGを利用して いるので、 SVGの自由度が高めになっていV E SVGを出し分けるJSXを利用して、 (普通なら実現しにく い)
動的なビジュアルを作る
#burikaigi_m
#burikaigi_m SVGでクリエイティブコーディング return ... = / / / = =
= = = = = = < return ... = / / / = = = = = = = < return ... = = / / / = = / / = = / / / < { }> < { blockSize blockSize blockSize b < { / } { / } { / } { < { / } { / } { / } { } </ > // T 270 if (value ) < { }> < { blockSize blockSize blockSize blockSize < { / } { / } { / } { } < { / } { / } { } /> </ > // X if (value ) < { }> < { } { blockSize blockSize blockSize bloc {/* < { } { blockSize blockSize blockSize < { } { blockSize blockSize blockSize bloc </ > // O 2 2 2 2 2 2 2 2 2 0.25 2 2 2 2 2 2 2 2 0.55 2 2 2 2 2 2 2 2 g groupProps path d rect x blockSize y blockSize width blockSize height blockSize rect y blockSize width blockSize height blockSize fill g g groupProps path d rect y blockSize width blockSize height blockSize fill rect width blockSize height blockSize fill g g groupProps path fill d path fill d path fill d g color color color color color color `M0 ${ } L 0 0 A ${ } ${ } 0 0 1 ${ `M${ } 0 L ${ } 0 A ${ } ${ `m${ } ${ } ${ } ${ `M${ } ${ } 0 0h${ }L${ `m${ } ${ } ${ }-${
#burikaigi_m return ... = / / / = = =
= = = = = < return ... = / / / = = = = = = = < return ... = = / / / = = / / = = / / / < { }> < { blockSize blockSize blockSize b < { / } { / } { / } { < { / } { / } { / } { } </ > // T 270 if (value ) < { }> < { blockSize blockSize blockSize blockSize < { / } { / } { / } { } < { / } { / } { } /> </ > // X if (value ) < { }> < { } { blockSize blockSize blockSize bloc {/* < { } { blockSize blockSize blockSize < { } { blockSize blockSize blockSize bloc </ > // O 2 2 2 2 2 2 2 2 2 0.25 2 2 2 2 2 2 2 2 0.55 2 2 2 2 2 2 2 2 g groupProps path d rect x blockSize y blockSize width blockSize height blockSize rect y blockSize width blockSize height blockSize fill g g groupProps path d rect y blockSize width blockSize height blockSize fill rect width blockSize height blockSize fill g g groupProps path fill d path fill d path fill d g color color color color color color `M0 ${ } L 0 0 A ${ } ${ } 0 0 1 ${ `M${ } 0 L ${ } 0 A ${ } ${ `m${ } ${ } ${ } ${ `M${ } ${ } 0 0h${ }L${ `m${ } ${ } ${ }-${ SVGでクリエイティブコーディング h vercel/ogでは画像アウトプット前の中間状態にSVGを 使っているので、 それを想定して書G h これらのパターンをランダムに並べている
#burikaigi_m 画像の色を考慮したビジュアルを作る 富山で食べた寿司がうまかった
#burikaigi_m 画像の色を考慮したビジュアルを作る 富山で食べた寿司がうまかった 色を考慮しない場合
#burikaigi_m 画像の色を考慮したビジュアルを作る 富山で食べた寿司がうまかった 特徴色を取得 輝度を特定の値に変更 グラデーションの値に利用 hsl(34, 28, 57) hsl(34,
28, 30)
#burikaigi_m 画像の色を考慮したビジュアルを作る 画像の各ピクセル情報から、 その画像の特徴的な色を取 り出し、 その色を画像の要素として利用すX 取り出した色をそのまま使うのではなく、 輝度を落として
利用すると使いやすa 画像処理は重いのでEdgeでは動かせず、 従来のサー バーレス上で動作、 または事前に保存しておく必要あり
#burikaigi_m 画像の色を考慮したビジュアルを作る import from import from import from const =
await const = await const = new const = const = new const = const = const = jpeg { FastAverageColor } ; { rgb2hsl, hsl2rgb } (imageUrl) image. () (image) jpeg. (uint8Array) (); [ , , , ] fac. (decoded.data) [ , , ] (r, g, b) (h, s, ) 'jpeg-js' 'fast-average-color' './utils' image imageArray uint8Array decoded fac r g b a h s l themeColor 0.3 fetch arrayBuffer Uint8Array decode FastAverageColor getColorFromArray4 rgb2hsl hsl2rgb
#burikaigi_m まとめ c Web技術で作れることと、 Webのように作ることを混同 しない方がよe c エンジニアリング的な視点とデザイナー的な視点を混ぜ て、 ちょっと凝った画像生成ができるかもしれない
#burikaigi_m Thank you!