ChatGPT にコンテキストに沿った代替テキストを生成してもらった

こんにちは、たじまん ( @schktjm) です。

この記事は、 ZOZO Advent Calendar 2023 の 4 日目の記事です。

はじめに

タイトルの通り、この記事では ChatGPT に代替テキストを生成してもらった話を書きます。 そして、最終確認をしようとした今、1日の上限に引っかかってしまい、もしかしたら何もできていないかもしれないです。

ChatGPT-4 では、テキストだけではなく画像やインターネット通信を含んだプロンプトを入力できるため、画像を渡すだけですぐ画像の説明をしてもらうことができます。しかし、代替テキストとなると話は別物になります。

アクセシビリティ文脈における代替テキストとは、技術支援ユーザーや直接画面を見ることができないユーザーに対して、画像の内容を伝えるためのテキストです。代替テキストは、画像の内容を伝えるためのものであるため、画像の内容を説明するだけではなく、コンテキストに沿った画像の意味や目的を伝えることも重要です。

例えば、以下のような画像があったとします。

検索窓の画像 プレースホルダーに検索すると書いてあり、検索窓の右側に虫眼鏡アイコンが設置されている
検索窓

この場合の虫眼鏡アイコンの代替テキストは、 虫眼鏡アイコン ではなく、空文字列にするべきです。なぜならこのアイコンは装飾目的であり、意味を伝える物ではないからです。

また、以下のような画像があったとします。

ZOZOTOWN のキャプチャ ハートのボタンに紫色の枠線*1

このハートアイコンをクリックすると、お気に入り一覧画面に遷移します。そのため、このハートアイコンの代替テキストは ハート ではなく、 お気に入り一覧お気に入りを見る を設定します。そうすると読み上げツールは「リンク お気に入りを見る」と読み上げるため、支援技術ユーザーに対してこのハートをクリックすればお気に入り一覧を見ることができると伝えることができます。

このように、代替テキストには画像を説明するテキストそのものではなく、コンテキストに沿ったテキストが重要になります。

つくったもの

今回は、 GPT Builder を使って、代替テキストを生成する bot を作成しました。

Alt Text Designer

Alt Text Designer

この bot のテキスト欄に、画面のキャプチャとどの画像の代替テキストを出力させるかを入力すると、代替テキストを生成してくれます。と言いたいところだったんですが、試そうとしたところで 1 日の制限に引っかかってしまいました 🥲

そのため、試そうとしていたチャットのキャプチャを貼ります。

私「それではこの画像の右上の紫の枠で囲ってるアイコンの代替テキストを教えてください」(画像添付) GPT「紫の枠で囲まれたアイコンがどのような機能を持っているか、説明していただけますか?その機能に応じて適切な代替テキストを提案させていただきます。」私「このアイコンをクリックすると、お知らせ一覧のページに遷移します」GPT「 この場合、アイコンに適切な代替テキストは「お知らせ一覧ページへ遷移」となります。このテキストは、アイコンがお知らせ一覧ページへのリンクであることを正確に伝えるものです。」
ChatGPT のチャット画像*2

このような感じで、コンテキストによって代替テキストを生成してくれるはずです。(きっと)

プロンプト (実装方法)

あまり自分がプロンプトエンジニアリングに詳しくないため、テンプレートに落とし込めませんでしたが、以下の方法で実装しました。

  1. プロの web デザイナーとして、 web デザイン中の画像の代替テキストを考えさせる。
  2. コンテキスト別の画像を用意し、その場合の代替テキストの役割を教えながら答えに辿り着かせる。
    1. 装飾の意味で使われている場合の画像の代替テキストの例
    2. インタラクション後に何が起こるかを説明する代替テキストが良い例
    3. 配置されている位置によって全てを説明する必要がない代替テキストの例
  3. 今までの学習をもとに代替テキストを出力させる。

a, b, c の画像はそれぞれ以下のような画像を用意しました。

検索ボックスの画像、検索ボックスの右に配置してある虫眼鏡に紫色の枠線がある
a. 装飾の意味で使われている場合の画像の代替テキストの例

ZOZOTOWN トップページのキャプチャ、ヘッダーのハートアイコンに紫色の枠線がかかっている
b. インタラクション後に何が起こるかを説明する代替テキストが良い例*3

ZOZOTOWN トップのキャプチャ、カルーセルバナーの現在地を移動するボタンに紫色の枠線が書いてある
c. 配置されている位置によって全てを説明する必要がない代替テキストの例*4

チャットの内容も出力しようとしたところ、ローディングが終わらないため後日追記しておきます 🙇

まとめ

今回は、 ChatGPT にコンテキストに沿った代替テキストを生成してもらった話を書きました。

まだ場合によっては以前の会話を全部無視された出力がされるのでもう少しプロンプトを工夫する必要がありそうですが、代替テキストの自動生成は簡単にできそうです。

また、今回は画像から指定したものの代替テキストを生成させる、という手法をとったため、 figma プラグイン化や Chrome 拡張化などの応用ができそうだなと考えています。次回作にご期待ください。

最後まで読んでいただき、ありがとうございました。

裏話

このアドベントカレンダーの話題はわりと早く決まっていたのですが、2 日前に用意しようとしたところ ChatGPT Pro プランの加入が自由ではなく wishlist になっていたのを知り絶望をした時のツイートがこちらです。

そこで、もともと考えていた figmaプラグイン作成にしようかどうか悩んだですが、今欲しいプラグインが思い浮かばず途方に暮れていたところ、課金ユーザーから招待コードをもらい、get the ことなきでした。

やはり前もって準備をしておくことは重要ですね、これからアドベントカレンダー書く方はぜひ参考にしてください。

*1:画像の一部をマスクしています

*2:画像の一部をマスクしています

*3:画像の一部をマスクしています

*4:画像の一部をマスクしています

CSS だけでスクロールしたタイミングにだけ影がつく実装の解説

この記事は ZOZO Advent Calendar 2022 カレンダー Vol.6の16日目の記事です。

はじめに

こんにちは、たじまです。

この記事では、スクロールした時にだけ影が影がつく実装を JavaScript を使用せず CSS のみで実装する方法の解説書こうと思います。

このヘッダーの下についているような影です

もし違っていたらコメントいただけると嬉しいです!

ソースコード

まずは実際のソースコードを添付します。

時間がある方はプロパティを変えたりして遊んでみてください!

https://codepen.io/schktjm/pen/PoaMQjZ

(Codepen 展開されないの知らなかった...)

解説

スタイルを一部切り抜いてきました。

.scrollbox {
  max-height: 200px;
  width: 250px;
  overflow: auto;

  background: linear-gradient(white 30%, transparent),
    linear-gradient(transparent, white 70%) 0 100%,
    linear-gradient(rgba(0, 0, 0, 0.3) 15%, transparent),
    linear-gradient(transparent, rgba(0, 0, 0, 0.3) 85%) 0 100%;

  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  background-repeat: no-repeat;
  background-color: white;
  background-attachment: local, local, scroll, scroll;
}

これをみてもらえると分かるように、今回 box-shadow を用いた実装にはしていません。

今回影の部分になっているのは background に指定している linear-gradient です。詳しくみていきましょう。

今回ポイントなのは background に指定した4つのグラデーションと background-attachment プロパティです。

魔法1. background-attachment とは

先に background-attachment の解説をします。

background-attachment とは背景を指定した要素がスクロール可能な時に、背景を要素と一緒にスクロールするかビューポートに固定するかどうか指定する CSS プロパティです。

developer.mozilla.org

local: 背景は要素の内容に対する相対位置で固定されます。要素がスクロール機構を持っていた場合、背景画像は要素の内容とともにスクロールします。背景画像の描画エリアと配置エリアは、それらを囲む境界ではなく、要素のスクロール可能なエリアを基準にします。

scroll: 背景は要素自身に対する相対位置で固定され、内容と共にスクロールしません。 (要素の境界に対して効果的に張り付きます。)

つまりまとめると、背景に指定した4つのグラデーションのうち、前2つは要素と共にスクロールし後ろ2つは固定されスクロールされません。

魔法2. 背景の4つのグラデーション

background はカンマ区切りで複数の背景を指定することができます。

  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;

つまりこの記述は、縦幅が 40px の背景が2つと 縦幅が 14px の背景が2つ存在することがわかります。

4つの背景

  background: linear-gradient(white 30%, transparent),
    linear-gradient(transparent, white 70%) 0 100%,
    linear-gradient(rgba(0, 0, 0, 0.3) 15%, transparent),
    linear-gradient(transparent, rgba(0, 0, 0, 0.3) 85%) 0 100%;

またコチラの記述では背景のグラデーションは

  1. 上から 30% の位置で白から透明になるグラデーション
  2. 上から 70% の位置で透明から白になるグラデーション
  3. 上から 15% の位置でグレーから透明になるグラデーション
  4. 上から 85% の位置で透明からグレーになるグラデーション

であることがわかりました。

4つの背景

魔法のひもとき

なんとなく見えてきました。

つまりこの background は 要素と共に移動する2つのグラデーション と、スクロールせずに固定される 2つのグラデーション であることがわかりました。

図で表すとこういう感じになっています。

からくり

スクロール位置がトップにある場合は、background-attachment の値は local, scroll とはずトップに配置される結果、白色のグラデーションがグレーのグラデーションを覆い見えなくなっていました。 下部にいた時も同じ原理で、下側の白色のグラデーションしか見えていませんでした。

よってスクロール可能な時に box-shadow のような影をつける時ができました。

グラデーションの色を変えると確認できました!

色を変えたバージョン

おわりに

background-attachment は今日で初対面だったため少し間違った紹介をしているかもしれないです。 その時は是非コメントか Twitter で教えてもらえると嬉しいです!

参考にした記事

https://codepen.io/evank/pen/wWbRNO

現場猫の GIF を作った

これは ZOZO Advent Calendar 2022 カレンダー Vol.3 の 6日目の記事です。昨日の投稿は @YasuhiroKimesawa さんの「FourKeysを捉え直す」でした。

こんにちは、たじまです。

みなさん業務に関係したり新しい技術について語っていますが、私は一旦肩の力は抜いたネタ枠を提供しようと思います。

完成物

はじめに

みなさん、 Adobe を知っていますか?

最近、左利きのエレンという私の好きな漫画で、全ての広告は Adobe から生まれたという名言が生まれたあの Adobe です。

その言葉の通り Adobe はさまざまなクリエイターが使用しており、我々 ZOZO のデザイナー陣をはじめとしたクリエイターも違いはありません。

https://1000logos.net/wp-content/uploads/2021/04/Adobe-logo.png

しかしながら、私は今まで Adobe を使ったことがありませんでした。 デジタルでイラストを描いたことがなければ写真を撮る趣味もないため学割という貴重な期間を逃し、今まで過ごしてきました。

そこで figma や デザインシステムという言葉に敏感になっている今、 Adobe に入信し Hello World をすることをこのアドカレに捧げました。

(このタイミングでブラックフライデーで板タブを買いました)

現場猫を作りたい

そんななか TL は現場猫が流行っていました。

しかしながらただヨシ!という猫の静止画がでてくるだけでは何かもの悲しさを感じたので今回は Adobe を使用し GIF を作ることにしました。

Adobe illustrator の勉強の仕方

なんとイラレにはチュートリアルがたくさんあります。これをいちから行い基本的な使い方を知りました。

helpx.adobe.com

helpx.adobe.com

helpx.adobe.com

もともと figma は使用していたためなんとなくの使用感は似てるな〜と思いながらも画像をベクトル化したり いい感じ にする技術が詰まっていて課金要素感を感じました。

作り方

GIF の作り方はこんな感じです!

  1. 現場猫著作権の調査→ヨシ!
  2. 現場猫の静止画の調査→ヨシ!
  3. 参考にできる体の動きの動画または GIFを探す→帽子をかぶってないバージョンの現場猫の GIF を発見、参考にする→ヨシ!
  4. GIF の一枚一枚のイラストを illustrator で作り、画像にして photoshop で アニメーション化する→頑張った!
  5. 完成!

成果物は上にも貼りましたがこんなかんじです!

完成物

おわり

最初は AA を作ろうと思っていたんですが、普通にイラレを勉強した方が身になると思い技術何も関係ないものになっていまいました!

余裕を持って始めたつもりですが季節病を患ってしまいギリギリになってやっぱり予定調和なんだなという感じです。

今回ブラックフライデーで板タブも購入したので、LP のデザインから始めていこうかなと思います。

板タブ DECO 03
ブラックフライデーで買った板タブ

現場猫著作権について

問題はなさそうですが記述しておきます!

元ネタはくまみね(@kumamine)さんの書いた電話猫です。

これをもとにふたばちゃんねる(日本の画像掲示板)のふたば民が、

を掛けわせてコラージュを作ったことが現場猫の誕生の真相のようです。

また、くまみねさんは現場猫のコラージュについては自身のブログで触れていたため、気になる方はそちらから確認してみてください

どうもこんにちは くまみねです。

●オリジナルのキャラクターに現場猫のポーズをさせてもいいですか
●あれは現場猫のポーズをとっていましたけど許可しましたか

などの質問を受けたりすることもありますので図を描きました

※ちなみに現場猫のポーズに関して私の許可は不要です
※なぜなら私が考えたものではないからです

kumamine.blogspot.com

資料

現場猫(仕事猫)の元ネタは?【謎の猫の真相に迫る!】 - ゼネコン

【公式】Adobe Illustrator グラフィックデザインの定番ソフト

font-size の指定位置によって要素の高さが変わる問題

こんにちは、たじまです。ブログの名前をデフォルトから変えてみました。

さて、今回は先日 CSS と戯れていた際に発見した謎とその正体を備忘録の意味も込めてブログに綴ります。わかってから見直すと何故わからなかったのかがわからない現象に陥りますが過去の自分を助けるべく綴ってみようと思います。

また、もし見当違いなことを言っている場合はそっと教えていただけると飛んで喜びます。

問題: font-size の位置によって要素の高さが変わる

ピュアな HTML+CSS で実装された UI を JSX で再実装していました。 すると旧 UI と新 UI で下の図のような要素の高さが違うという現象が起きました。

f:id:tjmschk:20220219163408j:plain
font-size の位置によっての要素の差がでた

JSX ではテキスト部分を実装する際に <Typogrphy /> という font に関わるスタイルを指定するコンポーネントを使いました。 そのため元の実装と比べると font-size を指定する箇所が移動し、結果見た目が変わってしまいました。

( ※ 見比べしやすいように図では横に並べていますが display: flex; などはかけていません。)

codepen でも再現してみたので触ってみてください。

See the Pen why font-size by Tajima Sachiko (@schktjm) on CodePen.


原因: 要素の高さ判定

何故今回のような違いがでてしまったのかというと、要素の高さの算出方法に原因がありました。 inline box コンテンツの場合、行ボックスの高さ計算は line-height x font-size で算出されます。

( 正確には影響しているスタイルなどによりもっと複雑です。正確な情報は公式ドキュメント参考にしてください*1 )

つまり、 wrapper の要素で font-size をしている要素の高さは次のように算出されます。

font-size x line-height
= 12px x 1.5
= 18px

f:id:tjmschk:20220219163505j:plain
wrapper の要素で font-size をつけた場合

しかし Text を囲んでる要素で font-size を指定している場合は、要素の font-size は親から継承されている値を使うため次のように算出されます。

font-size x line-height
= 16px x 1.5
= 24px

f:id:tjmschk:20220219163546j:plain
テキスト要素で font-size をつけた場合

その結果 font-size の指定箇所によって見た目に違いが発生していました。

問題解決方法

簡単にですが解決方法を挙げます。

height をつける

要素に高さが指定されていなかった結果、中身のコンテンツによって自動計算されていました。 そのため高さを指定すれば解決します。

フレックスコンテンツにする

高さを指定するものと基本は同じですが、フレックスボックスレベルに従って要素がレイアウトされるとフレックスコンテナーの高さに要素が引き伸ばされるため有効な手段です。今回の場合では wrapper 指定している CSSdisplay: inline-flex; を付け足すことで同じ高さになります。

そういうものだと理解する

もちろん理解すれば問題も発生しません。

おわりに

既存 UI の再実装により HTML+CSS の仕様についてひとつ詳しくなりました。複雑なのでブログには載せませんでしたが、 W3C のドキュメントにもっと詳しい inline box の高さの算出方法が載っていたため気になる方はそちらもご覧ください。

CSS Inline Layout Module Level 3

また文中に発生する単語は MDN や W3C の単語をそのまま引用しているだけなのでごちゃ混ぜになっている可能性があるため意味わかんねえよという時はそっと教えてください。

感想

実装した当時は何が起こっているのかさっぱりわかりませんでした。助けてくださったみんなには感謝の気持ちしかないです。 正しいソースを探すために MDN を飛び越えて W3C を初めて読み込んだのが楽しかったです。

2021年ふりかえり

f:id:tjmschk:20211231180802p:plain

はじめに

こんにちは、たじまです。今年度が始まったころに出した 2021年の目標でお話ししたように、年度末ではなく年末に目標を振り返ってみようと思います。

一年区切りでやらないのかの理由としては年末に年納めの雰囲気を感じたいからです。小さい頃は冬休みがあり、家族でスキーに行き、大晦日に頑張って夜更かしをし、近くの小さい神社に除夜の鐘を突きに行っていましたが、大人になるにつれそういった季節を感じる瞬間が少なくなってきたのが少し寂しくかんじますね。

こちら、目標記事です。

tjmschk.hatenablog.com

私は人を見て良いと思ったものを真似することをよくやってしまうのですが、この目標を書いたときいろいろな記事を参考にしすぎて構成がそっくりになってしまい、当人からツッコミをもらってしまったので、 自戒の念を込めこの記事を書き終えるまでは TL に流れてくるふりかえりブログを読まない ようにしています。

丁度、この記事を書きながら聞いていたゆる言語学ラジオの忘年会ライブでは、水野さんも堀本さんも構成を作る能力に関しては双方負けていない自負があると仰っていました。話の構成を作る能力は魅せる能力に比べて努力で伸ばせるものであるから負けたくないとの事です。私も優れた人の真似ばかりするのではなく自分の能力を上げていかないとなぁと考えたラジオでした。

ゆる言語学ラジオ忘年会ライブ【流行語大賞決定&ひたすらエモい話】 - YouTube

長くなってしまいましたがそれでは本編参ります。

OKR 評価

O: Web フロントエンドの知識と経験を得る

Key Results 達成率
KR-1 60%
KR-2 0%
--- ---
総合 30%

この項目に関しての反省点は、学生から社会人へとライフステージが変わっていく中で学習リソースの変化を予測できなかったこと、目標立てた時点で具体的なものが自分で分かっていなかったことが原因だと考えられます。SNS を見ていると強い人は OSS コントリビュートしてるし、 bio に書いてあると強そうに見えるしといった理由でこの KR を設定しました。しかし常日頃から GitHub を見たりする習慣もなければ、一番難易度が低いといわれる英語翻訳も自信がなく積極的に参加することができませんでした。

また、社会人になりプロダクション開発に参加すると、趣味開発をしていた時とはインプットする内容が変わり、最先端の技術よりもリリースされてからいろんな会社で先行導入例があり散々擦られている技術だったり、関わっているプロダクションに導入可能かどうかといったものを多く調べるようになりました。そのためこの一年企業さんのテックブログの読んだ本数は学生の時と比べ倍以上になってると思います。

来年は今年得た反省を踏まえ、実情に合って現実的でかつ現在の自分より少し高い目標を立てたいと思います。

O: 自分の技術力を可視化する

Key Results 達成率
KR-1 0
KR-2 0.22%
--- ---
総合 0.11%

ひどいですね、自己最低評価です。 KR-1 のポートフォリオサイトは完全に忘れていました。今年の前半は少なくともやるぞと Figma をこねくり回していたんですが社会人が楽しくすっかり忘れこの記事を作る際に目標記事で思い出しました。反省です。

KR-2 は社会人になる意識もありあえて高めに設定していましたが去年同様、アドベントカレンダーの時期しか書かないという結果になりました。アドベントカレンダーを書くことが経験になり技術ブログに向けた心理的ハードルは低くはなっているのにこの時期以外にかけないのはモチベーションの問題だと思うので時折目標を見直して頑張ろうと思います。

O: 心身を健やかに保つ

Key Results 達成率
KR-1 51%
KR-2 100%(?)
KR-3 100%
--- ---
総合 83%

達成 👏

KR-1 の内訳を挙げると、リングフィット7回、ランニング 22 回、筋トレをカウントしていないのでランニングと同じ 22 回として 51 回です。しかしこれは運動にはまってた4~7月がほぼすべてで夏暑くなってランニングの習慣をやめて以降、一切やっていないのが反省です。

今年の Run

KR-2, KR-3 は主に心の健康に関しての目標です。KR-2は複数という曖昧な設定にしてしまいましたが精神的な依存先を増やすという目標をもって生活でき、所属コミュニティの分散に成功できたので 100% にしました。

旅行に関しては当時のコロナ生活で我慢していた心の叫びをうまく発散し楽しむことができました。

食パンを持った手 クマノミ
ダイビングでクマノミに食パンを食べさせている様子

以上が今年(4 ~ 12月)の目標達成度合いと振り返りでした。

その他

反省はここまでにして記憶に残った面白かったものをダダ流しします。

今年のおすすめ読んだ漫画

(一つ一つ語ろうと筆を執ったのですが書き終えるよりも前に年が越しそうだったので断念しました。)

連載中

完結しているもの

読み切り

  • 地獄楽
  • 皇の器
  • クローゼットガール
  • 赤錆森

ゲーム

今年は AmongUs にはまりました。幸いなことに週末になると AmongUs が開催されるサーバーを友人が紹介してくれ他おかげで楽しくぷれいすることができました。

また人狼ゲームを見ることにはまりました。戦法など覚えられたらオンラインゲームで参加したいなと思っています。

お酒

今年は取り寄せでクラフトビールをいろいろ飲みました。実は会津にいるときは少し外に出ればおいしい日本酒が飲めたので、ビールを飲むことがあまりなかったです。 東京に来てからはオンラインで帰る日本酒があまりないためクラフトビールを飲んでみました。その他東京で飲めるおすすめなお酒あれば紹介してください。

昨日飲んだ桃のクラフトビール

おわりに

この前社会人になったと思ったらあっという間に年末になってしまいました。 (卒論に取り組む前の)学生の頃と比べると自由に使える時間が少なく感じるし、業務中にプログラミング意欲が満たされてしまうとわざわざ土日にやらなくてもいいかという気持ちになりがちでした。

来年は目標を社会人向けかつ自分ができそうな目標に改め頑張っていこうと思います。

最後までお読みいただきありがとうございました。

Figma の SVG アイコンと GitHub リポジトリを自動同期する

f:id:tjmschk:20211219231552p:plain この記事は ZOZO Advent Calendar 2021 の 20 日目の記事です。

はじめに

こんにちは、田嶋です。この記事は ZOZO のアドカレの記事2本目です。最近はポケモン自作PCのセットアップに勤しんでいます。フロントエンドエンジニア全然できてません。

前提

今回は FigmaGitHub リポジトリSVG アイコンを自動で同期させ、アイコン管理を楽にしちゃおうという記事です。

タイトルでは自動同期と言ってますが、Figma が変更されたかどうかの検知ではなく cron での定期実行でリポジトリFigma の最新に合わせるすることで、自動同期を実現しています。

こちらの記事が大変参考になりました。GitHub か GitLab かの違いなのでもうほぼ二番煎じです。

inside.pixiv.blog

この記事で述べられている Github Action の figma-action ですが、現在はメンテされておらずアーカイブされていました。一応自分でも使ってみましたが上手く動かないようでした。

方法

実現方法について簡単に説明します。

1. Figma API を叩けるようにする

Figma DevelopersAPI を確認することができます。

Figma のファイルは node と呼ばれる木構造で構成されています。 node は node.typeRECTANGLECOMPONENT など判別することができます。今回使用する Figma ファイルは下図のレイアウトです。今回は Page1 の node に 背景に使っている Rectangle 1 と Icon のコンポーネントが複数あるという構成で、フレームにしていないため Icon は Rectangle の子ではなく兄弟です。

白い四角の上に8つのアイコン
Figma 上に作られたアイコン

2. Node.js で SVG をダウンロードしてくる CLI を作成する

FigmaAPI では子要素以下のファイルを直接ダウンロードする方法がないため、以下の階構成にしました。

  1. Icon を構成している node の id name を取得
  2. id を使用し画像取得用 API を叩き画像URL を取得
  3. fs を使用しローカルに画像をダウンロード

以下がコードです。

require("dotenv").config();
const fetch = require("node-fetch");
const fs = require("fs");

const baseUrl = "https://api.figma.com/v1/";
const figmaToken = process.env.FIGMA_TOKEN;
const fileId = "YhHWg9mZ6GdKkseHAAS1gw";

// Figma ファイルの API から component の ID を取得
const getComponentIds = async () => {
  try {
    const res = await fetch(`${baseUrl}files/${fileId}`, {
      headers: {
        "X-Figma-Token": figmaToken,
      },
    });
    const data = await res.json();
    const { components } = data;
    return components;
  } catch (error) {
    throw error;
  }
};

// Id から画像の URL を取得
const getImageLinks = async (component) => {
  try {
    const componentKeys = Object.keys(component).join();
    const res = await fetch(
      `${baseUrl}images/${fileId}?ids=${componentKeys}&format=svg`,
      {
        headers: {
          "X-Figma-Token": figmaToken,
        },
      }
    );
    const data = await res.json();
    const images = Object.keys(component).map((key) => {
      const { name } = component[key];
      const link = data.images[key];
      return { name, link };
    });

    return images;
  } catch (error) {
    throw error;
  }
};

// ローカルに画像を保存
const downloadImages = async ({ link, name }) => {
  const res = await fetch(link);
  const data = await res.buffer();
  fs.writeFileSync(`../src/${name}.svg`, data);
};

const main = async () => {
  const component = await getComponentIds();
  const images = await getImageLinks(component);
  images.forEach(async (image) => {
    await downloadImages(image);
  });
};

main();

3. Github Actions で定期実行する

あとは Github Action で定期的に上記のコードを実行するだけです。猿でもできますね。(私は二時間くらいここで躓きました。)

説明できることが少ないためコードを載せておきます。

name: Export SVG from Figma
on:
  schedule:
    cron: "0 0 * * *"

jobs:
  actions:
    runs-on: ubuntu-latest
    env:
      FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }}
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: node setup
        uses: actions/setup-node@v2
        with:
          node-version: "12"
      - run: cd script; npm install
      - run: cd script; npm run start
      - name: Commit
        run: |
          git config --local user.email "github_actions@example.com"
          git config --local user.name "GitHub Actions"
          git add .
          git commit -m "downloaded from Figma"
      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.TOKEN }}`
          branch: master

GitHub Action の schedule は UTC なためこちらじゃ JST の 9:00 に実行されます。あえて 0:00 (UTC) にしたのは起きている時間のほうがバグった時に対応できるからと思たという言い訳です。

まとめ

作成したコードはこちらになります。

github.com

今回は簡単な Figma ファイルで試したためもっと複雑な要求に対応するためにはもう少し改良を加える必要があります。例えば Solid Outline のアイコンはそれぞれ別に管理したいなど。しかし適切な API とドキュメントが提供されているため改良は容易にできそうです。 また curl 芸人ではないため、今回は Node で画像をダウンロードするスクリプトを書きましたが、 Github Actions で完結する方法もあります。

最後に

アドカレ2本目を書くことにあたって実は他に以下の二つのネタを用意していました。

  1. 社内(実質)独自言語の VSCodeシンタックスハイライトをつくる
  2. Figma Branching を使ってみる

しかし 1 はあまりに複雑で簡単にできなさそうだなと諦めたのと、 2 は Beta 版なため Figma の Organization プランでしかつ買うことができず、個人では契約することができなかったので諦めて前から気になっていたこちらをやってみることにしました。

私の所属している部署ではデザインツールは XD が使用されていますがこうしてアドカレで Figma の利便性を訴え布教をしていきたいです。

参考にした資料

no such file or directory, open の理由を知る - Qiita

node-fetch - npm

https://www.figma.com/developers/api

Github Actionで定期的にファイルをリポジトリにコミットさせる – nozograph

GitHub Actions ワークフローで処理を定期実行する方法 | gotohayato.com

平凡なフロントエンドエンジニアの Flutter 入門

この記事は ZOZO Advent Calender 2021 の6日目の記事です。ちゃんと事前に記事を用意してなくてすみません!!

はじめに

こんにちは、たじまです。 今回は前から興味を持っていた Flutter に入門してみました。普段業務ではフロントエンドエンジニアをしていて、他の職種について触れる機会がなかったため「 Flutter 触れば iOSAndroid エンジニアの気持ちがわかるようになるやろ!」とアドカレを機に体験してみました。(これは両アプリエンジニアに怒られそうですね。) 内容的に「これをやりました!楽しかったです!」で終わりそうなのでできるだけフロントエンジニア目線で感想を述べてみたいと思います。

f:id:tjmschk:20211206211622p:plain
初めての Flutter アプリ!

github.com

やったこと

Webと比べたときのアプリの大きなメリットというのはやはり、アプリ内要素指でタッチしったり指でスライドしたときのぬるっとしたものを掴んでいる UX(UI?) です。 そこで、あの体験を再現すべく Hello World から始めてみました。

勉強で参考にしたもの

zenn.dev

kazutxt さんのこちらの本が大変参考になりました! 初級編しか読めていないですが大変詳しく段階的に書かれていてわかりやすかったです。

できたもの

carousel_slider といいうライブラリを使って作ってみました。 面倒臭い印象があるカルーセルを一瞬でつくれました。

youtu.be

感じたこと

Hello World しながら感じたことを時系列順に述べてみます。

開発環境まわり

  1. Xcode のインストールが無限すぎる。
  2. AndroidiOSエミュレータを立ち上げようとしたが、マシンスペックが足りずに Mac が落ちた。フロント開発だと Chrome と Node.js さえ起動できればいいので MacBookAir で耐えていたが限界。実機で試してみる。
  3. iOS にビルドする際に開発チームや iPhone 側で開発元を許可しないといけないということが新鮮。
  4. Android は大昔の Xperia 端末しか持ってないので断念。ただ web と ios は同じアプリが動いたので感動。

開発体験

  1. 軽く触っただけだが Container のような element が CSS のプロパティを型として持っているため、文字を打つと補完ができてわかりやすい。また <bold> や <h1> みたいな element としての意味とスタイルを持ってしまったりしているような古の tag がないため綺麗に設計できそう。
  2. 見た目の構造は DOM Tree を直接書いているような感じで分かりやすかった。class にはあまり馴染みがないが名前などが CSS のプロパティに似ているため直感的にわかる。
  3. Center で左右だけじゃなく上下の中央揃えになる感覚が新しい。
  4. google だから? Material Design の色々がデフォで入っていて馴染みの感覚ができた。
  5. icon の自動生成だったり VSCode での開発から Android/iOS/Web 全てにビルドできるのが開発障壁が下がっている気がする。
  6. ビルドが重い。私の MBA は常に悲鳴を上げている。

終わりに

思ってたよりも Dart という言語が分かりやすくとっつきやすい言語でした。 カルーセルの実装で終わってしまいましたが本当は上からカードが降りてきて左右に分け捨てるような UX を作りたいのでもうすこし色々試してみようと思います。それが終わったら PWA でも作って比較したいです。

自分のマシンが常に火を吹きそうな状態なため、ディスプレイの数を減らし並行で動いているアプリも終了したため開発環境がつらかったです。常にいいマシンが欲しいですね。

ありがとうございました!