【令和最新版】Illustratorで文字を中央揃えにする方法【整列で差をつけろ】

だいたい10年くらいイラレ触ってたのに今更気付いたので
お恥ずかしながら自分用の備忘録としてかきます。


こういうよくあるボタンを描いた時、
ボタンの枠で中央揃えしても文字のバウンディングボックスでかくて下が広くなっちゃうんだよな〜
一旦アウトライン化して位置図るか〜…🤔

という旧石器時代みたいな方法で毎度描いてたのですが

令和のイラレは進化していた!!!!

やってみよう

  1. [キーオブジェクトに整列]にしておく
  2. 整列パネルの右上メニューにある [字形の境界に整列] → [ポイント文字] にチェックを入れる
  3. ボタンの枠をキーオブジェクトにして[垂直方向に整列]

すると…

いい感じに中央揃えになってる!! Thank you Adobe…

キーオブジェクトをアイコンにすれば、
アイコン付きの文字列も天地中央揃えでキレイに揃います。

イラレは日々進化している

いやこれほんと全デザイナーが待ってたやつ…!一体いつ実装されたんだ!?
と思ったら2020年8月にアプデで実装されてたんですね

機能の概要 | Illustrator |(2020 年 8 月リリース)

イラレは常に進化し続けているのに、
自分は最初に覚えた知識のままアップデートできてないなと実感した日でした。日々勉強!おしまい!!

JSで(-8)**(2/3)を計算するとNaNになる

タイトルの通りなのですが、なぜかとある条件のべき乗を計算するとNaNが返ってくるので不思議に思って調べてみました(調べてくれたのは神谷)。

その条件は、基数が負なおかつ指数が分数 であること。

たとえば (-8)**(2/3) という計算は、答えは 4 なのですが、JSで計算をするとNaNが返ります。

(-8)**(2/3) // NaN

一体全体何が起きているのか?
答えは MdNのMath.powのページ に書いてありました。

// due to "even" and "odd" roots laying close to each other,
// and limits in the floating number precision,
// negative bases with fractional exponents always return NaN

最初の一行の意味はわからなかったのですが、要するに浮動小数点の精度の問題で 基数が負なおかつ指数が分数のときは静的にNaNを返すのがJSの仕様 ということみたいです

実際にMath.powで同じことをしても結果はNaNでした。

Math.pow(-8, 2/3) // NaN

試しに、指数の分数を分解して (3√(-8))^2 で計算してみると

Math.pow(Math.cbrt(-8), 2) // 4

正しく4が返ります。


そういえば、正の数の平方根の計算結果って±になりますよね。

√4 の答えは ±2 と学校で習った記憶がある。

Math.sqrt(4) // 2

この辺の計算って結構曖昧なのかもしれません

iOS Safari ではXHRで巨大なHTMLを読み込めない事がある

古き良き、サーバーサイドレンダリングなマルチページで一部分だけ動的に書き換える際に、HTML全体を非同期で取得して必要なDOMだけ差し替えるような実装をすることがある。

たとえば WordPress サイトなんかで、サーバーサイドは変更せずに簡易的な非同期遷移を実装しようと思ったらこういう実装になる。

const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://192.168.x.x/hoge/fuga', true);
xhr.responseType = 'document';
xhr.addEventListener('readystatechange', () => {
    if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        const html = xhr.response.querySelector('.hogehoge-selector').innerHTML;
        container.innerHTML = html;
    }
});
xhr.send();

注目スべきはここ

xhr.responseType = 'document';

document を指定することで xhr.response がDocumentで返ってくるので、いきなり querySelector なんかを使うことができるのだ。

こんな感じで実装されていたわりと古いコードがあったのだが、iPhone実機でエラーに遭遇した。

TypeError: null is not an object (evaluating 'xhr.response.querySelector')

readystatechange リスナー内の xhr.responsenull だというのだ。
xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200 という条件式の中にあるにも関わらず。

Webインスペクタのネットワークパネルでレスポンス内容を見ると正しくHTMLがレスポンスされているのも確認できる。

しかもこのエラー、毎回出るのではなく、5回に1回程度の割合で出るのでたちが悪い。

試しにDocumentではなく文字列で取得してみる

    if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        console.log(xhr.responseText);
    }

InvalidStateError: The object is in an invalid state.

xhr.responseText にアクセスすらできない状態で、エラー内容もよくわからない。

エラー文でググってみると、どうやらガーベジコレクションが行われたオブジェクトに対してアクセスしたときに出るエラーのようだ。まだ使ってないのにGCが発火してしまったらしい。

今回この事象に遭遇したのは2000行超あるかなり巨大なHTMLだったので、試しに500行くらいまで減らしてみると、案の定エラーが出ることはなくなって、正常動作が確認できた。

少しずつ行数を増やしていくと、徐々にエラーになる確率が増えていくような感じがあるので、やはりメモリ管理にバグがあるらしい。

手元の環境では、下記で発生することが確認できた

  • iPhone X : iOS 15.0, 15.0.1
  • iPad Pro 11インチ (第1世代) : iPadOS 15.0

Mac Safari や iOS シミュレータでは再現しなかったが、母艦の搭載メモリや起動しているアプリなど、条件によっては発生するんじゃないかとおもう。

行った対処法としては、

xhr.responseType = 'document';

これを使うのをやめて、textで取得し、 DOMParser なりなんなりで自分でDocumentに変換してやる。

xhr.responseType = 'text';
xhr.addEventListener('readystatechange', () => {
    if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        const parser = new DOMParser();
        const doc = parser.parseFromString(xhr.response, 'text/html');
        console.log(doc);
    }
});

もしくはレガシーコードは窓から投げ捨てて、素直に fetch で書き直してればこんなバグには遭遇しないのだ。

fetch('http://192.168.x.x/hoge/fuga')
    .then(response => response.text())
    .then(text => {
        const parser = new DOMParser();
        const doc = parser.parseFromString(text, 'text/html');
        console.log(doc);
    });

いまどきXHRなんて使ってんのが悪い。

Photoshopを使って3DCGつくってみよう

ここ数年3Dの作品をよく見かけるようになり、
やってみたくても中々ハードルが高くて躊躇していたのですが…
普段使ってるPhotoshopで3Dつくれるらしいぞ → 実際にやってみた!ので記事にしてみました。

用意するもの

  • Adobe Illustrator(作画)
  • Adobe Photoshop(3D作画)
  • Adobe Dimension(3D出力)

CreativeCroud課金者なら上記ぜんぶインストールできます
(※ちなみにPhotoshopでパス書く場合はIllustrator不要です)

主な流れとしては、
① Illustratorでパス書く
② Photoshopで3Dにする
③ Dimensionで3Dを編集する

の3工程です。

早速やっていこう

今回は私のキャラクター「おもち」を3Dにしたいと思います。

おもちです。白くてまるい。足が4本、角が3本あります。

1. パスデータをつくろう


Illustratorを起動してペンツールでキャラクターのシルエットのパスを書きます。
(※ Photoshopでパス描ける方はIllustrator使わなくてOKです)

パスを描くときは3Dにした際のガタつきを減らすため、
なるべくアンカーポイントを減らし、左右対称にするとよい感じです。
また、丸いシルエットにするためコーナーを角丸にしておきます。
(色は後で変更するのでわかりやすいよう水色にしています)

保存形式はaiでOK。体と顔パーツは別のaiファイルにしておきます。

2. Photoshopで読み込んで3Dにする

先ほど作成したaiファイルをPhotoshopで読み込みます。
解像度は300dpi、カラーモードはRGBカラーにしましょう。
(RGBカラー以外だと3D作成できません)


読み込み後はレイヤーを選択し、
メニューバーの[3D]→[選択したレイヤーから新規3D押し出しを作成]を選択します。
図がなんとなく3Dぽくなって、3Dメニューが出ます。


3Dメニューのレイヤー1を選択し、プロパティのシェイププリセットからピロー効果を選択します。すると何だか表面がぷっくりします。


次はプロパティのキャップに移動し
変数を[フロントとバック]、膨張の角度を[90°]強さは[20%]に設定します。
強さを上げるとふくらみが強くなります。


好みのふくらみ加減になったら、座標→座標を初期化をクリックして座標位置をリセットしておきます。


ここまでできたら書き出しましょう。
メニューバーの[3D]→[3Dレイヤーを書き出し]を選択します。
3Dファイル形式を[Wavefront|OBJ]に変更して保存します。


同じ工程で顔パーツも作成します。
すべてのパーツができたら、次はDimentionで3Dデータを編集します。

3. Dimentionで3Dを編集する

Adobe Dimensionを起動して、ファイル→開くで先ほど作成した体パーツの.objファイルを読み込みます。
その後、顔パーツの.objファイルを上にドラッグしてパーツが2つ並ぶように配置します。

ここから軌道カメラツールなどを駆使しつつ顔パーツを体パーツに埋め込みます。


↑軌道カメラツール。ぐるぐる回る

↑パンツール。近寄ったり離れたりする

遠近ツール。手前に寄せたり遠ざけたりする

カメラツールをいじりすぎて位置がごちゃごちゃになってしまったら
メニューバーのカメラ→ホームビューに切り替え(または⌘B)で初期位置に戻しつつがんばります。


顔パーツを選択し、緑色の矢印を選択して十字キー↑を連打。顔の位置を少しずつ上げます。
位置が定まったら次は赤色の矢印を選択して少しずつ横に移動させます。


カメラの視点を上に持っていき、顔パーツが半分埋め込むまれるよう調節します。
納得のいく位置に調整できたら、最後に顔パーツと体パーツをグループ化しておきます。

3Dの組み立てが完成したら後は質感と色を変えます。

マットな質感にしたいので、本体パーツをクリックして
スターターアセットの中にある[Adobe標準マテリアル]から[艶消し]を選びます。
プロパティのベースカラーを白色(RGB 255,255,255)に変更します。
顔パーツも艶消しの黒色(RGB 20,20,20)にしました。


ここまでできたら、あとは背景を合成してみます。

4. 背景を敷いてみる

右上のシーンメニュー内にある[環境]を選択すると、
環境プロパティがいじれるようになるので、ここで好きな背景画像をおきます。

背景を置いた後、アクションから
☑️ カンバスサイズを変更→画像の縦横比
☑️ ライトを作成→抽象
☑️ カメラのパースを合わせる にチェックを入れOKボタンを押します。


すると勝手に位置やライティングを調整して、背景に合うよういい感じに仕上げてくれます。すごい。
あとはお好みで位置や大きさなどを微調整しましょう。

完成したら、デザインメニュー横のレンダリングを選択し、
画質や書き出し形式を好きなものに設定して書き出します。

完成!!


レンダリングしたものがこれになります。
路地裏で猫ちゃんに遭遇したみたいでかわいい~!!

あとがき

Dimensionは今回初めて触ったのですが思ったより直感的に触れてなんとかなりました。
パッケージデザインのモックアップを作るのに適しているそうなので
次回はそっちでも遊んでみたいと思います。

そしてこの記事を書いている間に気がついたのですが、
実は近日中にPhotoshopから3D機能が削除されるみたいです。えっ…??

Photoshop の 3D 機能 | 廃止された 3D 機能に関するよくある質問

Photoshop22.2を使用すれば引き続き3Dを使えるみたいなんですが、
まさかこんなタイミングで削除のお知らせを見るとは…

やっぱりBlenderから逃げるなということなんですかね?あぁ〜〜…


Figmaでボタン作ったらVariantsで管理するといいかんじ

Figmaにはボタンなどのコンポーネントをまとめて管理できるVariantsと呼ばれる機能があるのですが
これを実際に使ってみたところとっても便利だったので覚書として書きました。
ちなみに昨年追加された機能なのでちょっと今更感ありますが、ご参考になればと思います。

Variantsってなに?

Webデザインでよく使うアイテムは大体コンポーネント化して使っていると思いますが、
その中でもボタンやリストなど「ぱっと見同じデザインだけど色やアイコンの有無でバリエーションがあるもの」
をひとつのグループにして管理できるよ!というのがVariantsです。

やってみよう

まずはボタンのコンポーネントを作成します。
Variantsは複数管理の機能ですので、コンポーネントを2つ以上つくり、コンポーネント化しておきます。


例として赤と青のボタンを作りました。

次はコンポーネントに名前をつけます。
名前をつける際は、ボタンのデザイン規則を意識してつけます。

今回つくったのは赤いボタンと青いボタンなので、
それぞれButton / Red、Button / Blue と付けました。規則は/で区切りましょう。

名前を付け終わったら、
Variantで管理したいコンポーネントをすべて選択し、Conbine as variantsを押します。

これでVariants化できました。

ちゃんとVariants化できたか確認してみましょう。

配置したボタンを選択すると右メニューに[Property1]が追加されてます。
(この名称はVariantsのところから後で変更できます)

このプルダウンを選択すると…

ボタンを切り替えることができました!👏

これを活用すれば、たくさんのデザインをVariantsで管理できます。

ちなみにドロップダウンではなくスイッチで切り替えもできます。

スイッチ切り替えにしたい場合は名前をつける際にon/offまたはtrue/falseにしましょう。
私はアイコンのあり/なしで使ってます。

[Variants]は使えるシーンがちょっと限られる機能ですが、
便利ですのでぜひ使ってみてください。

TypeScript+Rollupでビルドが終わらない

RollupでTypeScriptのビルド設定を書いていたら、なぜかrollupのビルドコマンドがいつまで経っても終わらず、ctrl+cせざるをえない状態になり、原因調査に時間がかかったので備忘メモ

症状としてはこんな感じ

ビルド自体は終わっている(標準出力)のに、プロンプトが返ってこない

エラーも何も出ないのでなんの情報もなく、途方に暮れた挙げ句は神に祈りながらMacの再起動までしてみたけどダメでした 🤷‍♂️

どうやらtypescriptの4.4.xにバグがあるみたいで、4.3.xや4.5.0のデイリービルドなら起きないようだ。

すでに PRが作られて おり、4.4.3でリリースされるみたいなのでもう少し待ってみるか

sass-loaderとdart-sassにまつわるfibersの話

tl;dr

用語について

現在npmで sass として公開されているパッケージはdart製のsassとなっています。旧来使われていたnode製のsassは node-sass として公開されています。

ここでは区別を分かりやすくするため、dart製のsassを dart-sass、 node製のsassを node-sass と呼び分けています。

本文

そもそもsass-loaderで何を設定しているのでしょうか。sass-loaderでdart-sassを利用する際はだいたい下記のように設定しているかと思います。

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        // ...
        use: [
          `// ...
          {
            loader: `sass-loader`,
            options: {
              implementation: require('sass'), // ここで `dart-sass` を読み込んでいる
              sassOptions: {
                fiber: require(`fibers`), // 大体の人がなんとなく一緒に読み込んでいる
              },
            },
          },
        ],
      },
    ],
  },
  // ...
};

まず implementation プロパティについてはsass-loaderのドキュメント に書いてあるとおりですが簡単にまとめると

  • implementation を設定しない場合、 node-sassとdart-sassの両方インストールされている場合、自動的に後者が読み込まれる
  • implementation を設定することで明示することができる

の2点かとおもいます。この「両方がインストールされている場合」というのは、プロジェクト内の package.jsondevDependencies などに追加されている場合以外にも他のパッケージの依存に入っている場合も含まれるので、基本的には明示したほうが良いでしょう。

では、なぜ dart-sass を利用する場合に fiber プロパティにfibersパッケージを指定しているのでしょうか。

node-sassにもdart-sassにも render()renderSync() というAPIがあります。これはどちらもscssからcssへコンパイルするための関数ですが、前者が非同期に実行され、後者は同期的に実行されます。sass-loaderでは render() が利用され非同期的にscssファイルがコンパイルされることになります。

しかし、 dart-sassでは非同期にに実行する render() が非同期実行のオーバーヘッドのため renderSync() より2倍近く遅くなってしまいます。これを避けるために、利用されるのがfibresです。

fibersはもともとnode.jsに非同期に関数を実行する仕組み(Promiseやasnyc/await)がなかった頃に開発されたものです。同期関数を非同期で実行することができる Promise に相当する機能があります。(他にもGeneratorに相当する機能もありますがここでは割愛します。)

速度の早い renderSync() 関数を非同期でするために、このfibersを利用する設定が前述した webpack.config.js です。ただしfibersは作者により使用を避けるべきとされており、node 16への対応もされていません。

まとめ

つまり記事の冒頭でまとめたように、 node 16 を利用するのであればfibersを利用することはできず、コンパイル速度の低下を受け入れざるを得ません。sass-loaderではdart-sassの場合に renderSync() を利用するIssueが立っているのでもしかするとsass-loader側で対応がなされるかもしれません。

ディスプレイを接続していないWindowsにChromeRemoteDesktopで接続すると重くなる場合はHDMIダミープラグを挿すと良い

自宅のWindows環境はファイルサーバ・DLNAサーバとして常時起動させています。

Windowsでなにか作業をすることはほとんどないので、いっそのことディスプレイを接続するのをやめることにしました。

たまに触るときはChrome Remote DesktopでスマホやMacからアクセスしていたのですが、どうもディスプレイを接続していない環境にChrome Remote DesktopでアクセスするとOS全体のパフォーマンスが著しく低下するようです。

原因はよくわかりませんが、ディスプレイを繋いでいれば快適に動くので、試しにHDMIダミープラグを買って挿してみると案の定快適に動作しました。

なんのために使う製品なのかわかってなかったですが、こういう使い方もあるんですね。

Amazonレビューを見ると、解像度の高いディスプレイを持っていないけど作業スペースを広く使いたい場合に、4Kのダミープラグを指し、あえてリモートで接続することで疑似4Kで作業できるため、自宅環境が整っていないリモートワーカーに人気があるらしい。

MacBookで4K120Hzを出力できる組み合わせ

現行のMacBookシリーズは高解像度かつ高リフレッシュレートな映像出力が不安定で、マシン・OS・接続方法の組み合わせで出力できたりできなかったりする。
それを備忘録的にまとめてみます

① MacBook本体

そもそもの話なのだけど、MacBookやiMac本体のディスプレイは解像度こそ高いがリフレッシュレートは60Hzです。
FHD@120Hz程度ならどんなMacでも出力可能ですが、4K@120Hzとなると4倍の演算能力が必要になるのでマシン自体が限られてくる
具体的に言うとIntel Graphicsでは演算能力が足りず出力不可能です

4K120Hz出力ができるMacBookは、

  • M1 Mac
  • Radeonなどのグラフィックチップを積んでる Intel Mac

M1か16インチのIntelMacを選んでおけば間違いないです

6K@60Hzや8K@30Hzの出力が可能なグラフィック能力があれば理屈では4K120Hzも出力できるはずで、MacBook以外もこの理屈でOK
eGPUでもイケるみたいです

② MacOS

ここに1つ目の落とし穴があります

M1 Mac

BigSurで出力可能。それ以外に選択肢もないので迷うことはありません

Intel Mac

BigSurでは4K@120Hz出力ができません
おそらくソフトウェア的なバグがあるので、現時点ではCatalinaを使うことをオススメします

③ 接続インターフェース

ここにはThunderboltやUSB-Cの複雑すぎる規格とMacの中途半端な実装に落とし穴があります

4K@120Hzの転送をするために注目すべき箇所は

  • Thunderbolt3もしくはUSB4ケーブル
  • DisplayPort 1.4対応 (= HBR3対応)
  • ケーブルの端子は USB-C to DisplayPort

HBR3と記載のあるThunderbolt3であればスペックは足りているのですが、Macのソフトウェア的な問題なのか、 ディスプレイ側はDisplayPortでないと4K@120Hzで出力ができません
Apple純正のThunderbolt3ケーブルでも無理でした。
(M1 Macでは試せていないので、両端がUSB-CなThunderbolt3ケーブルでも出力可能かもしれません)

菅沼環境ではこのケーブルで4K@144Hzを確認してます
https://www.amazon.co.jp/gp/product/B083V6VMNM/


上記をすべて満たした環境で、対応したディスプレイに接続すればOK

システム環境設定

[ディスプレイ]

optionを押しながら 解像度の[変更]

[低解像度モードを表示] にチェック

とすると、リフレッシュレートの選択肢が現れるはずです

DisplayMenu等のアプリでも設定可能ですが、なぜか8bitカラー(ARGB8888)になってしまうので、システム環境設定から変更することをオススメします

nvmとかnodenvとかanyenvをやめてasdfにした

これまでnode環境はnvmで、他はpyenvやgoenvを利用していたのですが、nvmが .node-version ファイルに対応していませんでした。(.nvmrc で指定することはできませす。)
そこでいい加減nodenvに移行したのですが、せっかくなのでどうせなら新しい物をを使おうと思いasdfに移行しました。

anyenvの問題点ははただの「**envをインストールソフト」であり、nodenvやpyenvなどそれぞれの利用法を知っている必要があります。
asdfは実行環境ごとのプラグインを介して直接バージョンを管理するため
どの実行環境でも同様に扱うことができます。
ある日突然「PHPの5.3のバイナリが欲しい…」となっても使い方を迷う必要がありません。

例としてnodejsであれば

asdf install nodejs 16.1.0

Pythonであれば

asdf install python 3.9.5

でインストールが可能です。

また、nodejsであれば lts-fermium のようにタグで指定することも可能です。
自分はグローバルにインストールするものは「一番新しいLTSの最新バージョン」を利用することにしているので、非常に便利です。(nodenvではこれができませんでした。)
また、.asdfrclegacy_version_file = yes を追加することで .node-version なども自動的に読み込み、ディレクトリによって自動的にバージョンを切り替えることもできます。

注意点としては、ビルドする関係上、使用するプラグイン(実行環境)によって依存するライブラリがあるため、そのインストールは別途必要になります。

anyenvより圧倒的に使いやすいので、anyenvやその他のバージョン管理ツールを利用している場合は、asdfへの移行を強くおすすめします。