1/100 出雲大社
4年ぐらい前にもらったやつをくみたてた (色だけほぼ塗った状態で放置してたのを組み立てた)
画像アセットを使ってサイズ別に書き出しつつ、.icns ファイルと .ico ファイルを作るまで
1024px × 1024px で作るか、全部ベクター(シェイプ)で作る。
書き出し対象のレイヤー全体をグループに入れる。この範囲だけが有効の状態で出力される。
また、空のレイヤーマスクをつけることで書き出し範囲を画像全体にする。これをやらないと透明部分が削除されて書き出されるため、余白がつかない。
グループのレイヤー名を
16 x 16 icon_16x16.png, 32 x 32 icon_32x32.png, 64 x 64 icon_64x64.png, 128 x 128 icon_128x128.png, 256 x 256 icon_256x256.png, 512 x 512 icon_512x512.png, 1024 x 1024 icon_1024x1024.png
にする。これで 16x16 〜 1024x1024 まで全部書き出される。このとき .png24 にすると後述する iconutil が認識できないファイルができるので、普通に .png を指定する
ファイル→生成→画像アセットにチェックを付けて保存する。[PSD basename]-assets/ ディレクトリ以下に自動的に書き出される。
OS X 用のアイコンファイルは .icns という変な形式になっている。これを作るためには iconutil というツールをつかう。
iconutil は .iconset という png ファイルが入ったバンドルを .icns に変換するという動作をするため、まずは .iconset 形式にあうようにフォーマット(ファイル名)を変える。
cp -r foobar-assets icon.iconset cd icon.iconset cp icon_32x32.png icon_16x16@2x.png mv icon_64x64.png icon_32x32@2x.png cp icon_256x256.png icon_128x128@2x.png cp icon_512x512.png icon_256x256@2x.png mv icon_1024x1024.png icon_512x512@2x.png cd .. iconutil --convert icns --output icon.icns icon.iconset
Retina 用に @2x という名前のファイルがいくつか必要になる。これで icon.icns ができる。
Windows 用のは .ico という変な形式になっている。これを作るためには imagemagick が使える。
imagemagick に複数引数を与えて .ico を出力に指定すればいいだけなので、以下のようにできる。
convert \ ./foobar-assets/icon_16x16.png \ ./foobar-assets/icon_32x32.png \ ./foobar-assets/icon_64x64.png \ ./foobar-assets/icon_128x128.png \ ./foobar-assets/icon_256x256.png \ ./foobar-assets/icon_512x512.png \ ./foobar-assets/icon_1024x1024.png \ icon.ico
これで icon.ico ができる。ico 形式は基本ただの bitmap で、フォーマット上の制限で最大 255px × 255px までしか対応してないが、Vista以降はPNG埋め込みできるようになっているらしく、identify すると以下のような感じになる。
icon.ico[0] ICO 16x16 16x16+0+0 32-bit sRGB 121KB 0.000u 0:00.000 icon.ico[1] ICO 32x32 32x32+0+0 32-bit sRGB 121KB 0.000u 0:00.000 icon.ico[2] ICO 64x64 64x64+0+0 32-bit sRGB 121KB 0.000u 0:00.000 icon.ico[3] ICO 128x128 128x128+0+0 32-bit sRGB 121KB 0.000u 0:00.000 icon.ico[4] PNG 256x256 256x256+0+0 8-bit sRGB 121KB 0.000u 0:00.000 icon.ico[5] PNG 512x512 512x512+0+0 8-bit sRGB 121KB 0.000u 0:00.000 icon.ico[6] PNG 1024x1024 1024x1024+0+0 8-bit sRGB 121KB 0.000u 0:00.000
常に単に縦に並べるだけなら flex layout はいらない。
たくさんの項目をできるだけ詰め込む場合 flex layout はあらゆるスクリーンサイズへの対応で大きな活躍をする
min-width 及び適切な範囲でのグループ化を行なったら、あとは flex によるレイアウトに身をまかせる。
flex プロパティが指定されている要素を親に持つ要素に width: 100% や height: 100% を指定しても効かない (computed が 0 になる) ことがある。
flex box の仕様のなかでどこに書いてあるのかよく読めてないが、flex 指定された要素 (flex item) の見掛け上の大きさと、子要素に対する計算上の大きさが違うようで、どうしよもない。
同じことをやりたい場合、flex 指定した要素 (flex item) を position: relative に指定し、子要素を position: absolute; top: 0; left: 0; right: 0; bottom: 0; とすれば、この子要素の width/height が確定し、子要素の子要素 (flex 指定された要素の孫要素) では正しく width/height の % 指定が効くようになる。
flex item のサイズが計算されるさい、子要素のサイズを計算しようとするが、このとき子要素が%指定されていても、まだ親のサイズが決まっていないためゼロになる?
とりあえず、このテクニックは多様する。
https://github.com/cho45/Chemrtron
できるだけ雑にインデックス作成用のクローラを実装できるようにしたかったので、そのようになっている。
オフライン閲覧はあんまり考慮してないが、file:// でインデックス登録すればオフラインでも使えると思う (ネットワークよりもディスクサイズのほうが厳しいのでオフラインにあまり興味がない…)
レポジトリをクローンする場合 electron-prebuilt が必要。
npm -g install electron-prebuilt
git clone https://github.com/cho45/Chemrtron.git cd Chemrtron electron .
または https://github.com/cho45/Chemrtron/releases のページから .dmg を落としてくる。うまく動くかわからないが、こちらはランタイムを全て含むので electron-prebuilt や npm などは不要。
歯車アイコンまたはメニューの Preferences… から設定画面を開くと選択できる。
まだ並べかえを実装していないので、オンにした順に並ぶ。
マニュアル単位でインデクサを実装する必要がある。主要なものは実装済みでレポジトリに入れてあるが不完全かもしれない。対応済みの一覧
だいたいの場合 HTML で全メソッド/クラスへのリンクが張ってあるページがマニュアルに存在しているので、そのページをとってきて querySelectorAll とかで雑にリンク抽出すれば十分なインデックスをつくれる。
インデクサのコードは非表示の別ウィンドウで実行されるので、ある程度重い処理でブロックしても問題ない。
インデックスといっても転置インデックスではなく、検索対象文字列の一覧を正規表現でマッチをかけているだけである。
リファレンスマニュアルのようなものの検索の場合フルテキストサーチよりも、ある程度一貫性のある文字列を検索させたほうが余計なものがヒットしないので気持ちがいいと思う。
例えば Array.prototype.slice みたいなページを表示したいとき、arr sli とかだけでいいようにしたい。既に行きたいページが明確なので雑なクエリで確実に辿りつきたい。
https://github.com/cho45/Chemrtron/blob/master/indexers/nodejs.js
あたりを参考にして雑に書くと動く。もし動かない場合、View → Toggle Developer Tools とするか、設定から Developer Mode をオンにすると console と、インデクサ用のウィンドウが表示させるのでデバッグ可能になる。
~/.chemr/indexers/ に置いても読むようになっている。
MDN (Mozilla Developer Network) は HTML, CSS, JavaScript を横断して検索でき、ブラウザごとの互換情報とか、ポリフィル方法 (実装概略) とかも載っていて、とりあえずウェブ系ならこれを検索しとけば良い感じで便利。
クローラを内蔵していて、雑にインデックスを作るのが楽という方向性を目指しています。
せっかくなので Windows 版を作ろうとしたがうまくいってない。
バックグラウンドで自動更新するようにしたい。
昔 Chemr というリファレンスマニュアルをインクリメンタルサーチするアプリケーションを書いていた。最初の Chemr は HTML Help を読め RubyCocoa で実装していた。次はFirefox + Greasemonkey 上で動くユーザスクリプトとして実装した。そして Electron が流行ってきたので Electron 上で動くように実装しなおした。
諏訪大社に続き、仁科神明宮にも行ってきた。諏訪からは同じ長野県内ではあるがかなり離れており、駅からも30分ぐらい歩く。
現存する神明造社殿では最古で、本殿が国宝に指定されている。
神社はどの神社も式年遷宮で造りなおされる傾向があり古いものがそのまま残っているケースが少ない。この神社も300年前までは建て替えをしていたみたいだけど、その後は修繕をやって残っているらしい。
ちなみに神明造りに限らなければ、現存最古の神社は京都の宇治上神社で、こちらも国宝になっている (なおかつ京都の世界遺産を構成する1つ)。宇治上神社は5年前に行った
WebGL があるからね。ブラウザが業を背負ってくれるのだよ。
https://github.com/cho45/go-KX3-panadapter
KX3 (無線機) 用の panadapter (広域スペクトラムスコープ) の実装を WebGL でレンダリングするように変えた。
これまで go-gl を使って頑張っていたが、いつのまにか go-gl の構成が変更され、ビルドができなくなってしまった。
go には依存パッケージのバージョン指定を行う方法がないので (ないよね?) 最新に追従する以外の選択がないのだが、いきなりビルドが通らなくなるみたいな事態がおこるともうやる気がしない。
継続的にメンテするほどの変更は入れてないが「ときどき実用しているアプリケーション」が割とどうでもいい理由で壊れるととにかくやる気が失せる。なので、できるだけ壊れなそうなものに依存するようにしたい。
その点ウェブ技術に依存しておけば、あまりひどい非互換は入らないことが期待できるし、最悪壊れてもググれば非互換情報が見つかりやすく、対処しやすい。そしてそもそも JS で書くのでビルドできないような事態にはならない。
前のバージョンでは go-gl を使い、go で書いたプロセスで直接ウィンドウを作ってレンダリングしていたが、構成の変更により、go で書く部分は portaudio を使って任意のサンプリング周波数で信号のFFTを行い、WebSocket からストリームで投げ続けるというシンプルな動作を行うようになった。(44.1kHz 固定なら WebAudio + WebWorker でできそうだが、すくなくとも 96kHz サンプリングはしたいので WebAudio はつかってない)
ブラウザ側のJavaScriptでgoプロセスへ WebSocket の接続を行い、データを受信し次第 WebGL を使ってレンダリングを行う。
これにより go の部分の cgo 依存は portaudio のみになった。portaudio は非常に薄いラッパーなので将来非互換が入るような余地がほぼないと思われる。安心
別に go に限ったはなしではなく、ビルドができるできないとか依存がどうとか、とにかくダルイ。やらなくてすむことはやらないようにしよう。
rename コマンドで可能だぞ。rename コマンドは Perl の式でファイル名を置換可能だ!
「拡張子のないファイル」にマッチするシェルのglob表現は簡単ではないし、シェルスクリプトの for 文の文法はだいたいいつも忘れている。rename コマンドは Perl の正規表現という大変慣れたものを使え、sed や awk などと比べても安心感がある。
rename -v -n 's/^([^.]+)$/$1.txt/' *
置換が行われなかった場合リネームは行われない。-n はドライランなので実際に実行するときは外す。-v は verbose オプションで、つけておいたほうがいい。
この正規表現では . を含まないファイル名にマッチさせ、.txt をファイル名にあとに追加している。
Ubuntu の wiki によると
UNIXにこのコマンドがないこともあって余り知られていませんが、どのLinuxにも含まれています。
らしいが、本当のところどうなのかよくわからないぞ! すくなくとも Ubuntu では使用可能だ! なお OS X には含まれていない。
OS X では brew install rename で入るが、これは Ubuntu のパッケージのものとはまた別のバージョンである。ただし高機能版であり、-v -n オプションは互換性がある (-n の longname は Ubuntu 版では no-act だが、homebrew で入るものは --dry-run または --just-print となっている)。
ライセンスはどちらも This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. となっており Perl と同一 (Artistic License) のようだ。原版と同じ名称を使ってはいけないライセンスだった気がするが……
Ubuntu 版
# This script was developed by Robin Barker (Robin.Barker@npl.co.uk),
# from Larry Wall's original script eg/rename from the perl source.
homebrew 版
AUTHORS
Aristotle PagaltzisIdea, inspiration and original code from Larry Wall and Robin Barker.
となっており、Larry Wall (Original?) → Robin Barker (Ubuntu版) → Aristotle Pagaltzis (homebrew版) という感じで進化している雰囲気がある
上のように、スペクトラムのウォーターフォール表示ではよく下に1行追記して全体を上にスクロールさせていくみたいな見せかたをするが、全体の再描画が必須なため、かなり描画負荷が高い処理となる。
いくつか実装を書いてどのぐらい差がでるかを検証してみた。
http://cho45.stfuawsc.com/spectrum-performance/canvas-redraw-whole/
ctx.putImageData( ctx.getImageData(0, 1, canvas.width, canvas.height - 1), 0, 0 );
上のようなコードで canvas 全体を 1px ずらして、最後の一行に新しいデータによる putImageData() をさらに行う。
ピクセルデータを直接シフトさせるやりかただと、一番ナイーブで実装が簡単だが実際のところかなり遅い。
35ms/render ぐらい。
http://cho45.stfuawsc.com/spectrum-performance/canvas-double-dom/
canvas の 描画自体は1px * width だけを常に上書きする形で行い、全体のスクロールは DOM でずらす (ブラウザに再描画をやらせる)
わかりにくいので動画にするとこんな感じで、2枚の canvas 要素を margin で使って動かして、親要素で表示領域を制限 (overflow: hidden) してる。
4ms/render
http://cho45.stfuawsc.com/spectrum-performance/webgl-double-textures/
2枚 canvas とやっていることはほぼ同じだが、canvas の代わりに WebGL のテクスチャを2枚定義し、DOM の代わりにシェーダーを使う。
0.6ms/render
@cho45 デバイスがなくてコードを試せてないのですが、putImageData+getImageDataではなくてdrawImageにcanvas自身を渡してずらして一行描くのだと速くなりそうですがどうでしょう。
— Mayuki Sawatari (@mayuki) October 5, 2015と言われて、drawImage! そういえばそんなのも! という感じだったので試したらこれは十分高速だった。
0.6ms/render で WebGL でやるのと変わらないぐらい。
canvas へ広範囲に putImageData の繰替えしをするより DOM で移動させたほうが圧倒的に早いのがおもしろかった。
WebGL は面倒くさい分たしかに高速で、2D でも可能な限り使ったほうがよさそうだけど、直接文字のレンダリングができないとか (canvas に書いてからテクスチャとして転送する必要がある)、API 的に面倒とか、GLSL というシェーダー言語を覚える必要があるとか、難点もある。
とはいえ、面倒なぶん自力でチューニング可能なポイントが多いのでおもしろい。
もっと早くなる方法がありそうなら是非お知らせください。
だいたい作ってやる気がなくなってきたので動画にいちおうまとめた。
http://cho45.stfuawsc.com/misc/css3-sine-wave.html
CSS 自体では自由な曲線は描くことができないが、CSS animation では、animation-timing-function で cubic-bezier() を使い定義したベジェ曲線に従ってプロパティーの変化量を決めることができる。
なので、複数の animation する要素を組合せることで、全体としてサイン波を描くことができる。
ポイントは animation-timing-function はキーフレーム間 (1回のアニメーション全体ではない) に適用される点で、勘違いしているとひたすらハマる。
上記の例ではアニメーションさせたままだが、animation-delay に負の値を指定して animation-play-state: paused; を指定すれば止めた状態にもできる。
昔 keyString.js という KeyBoardEvent からなんとなく押されたキーの文字列表記になおすやつを書いたことがある。
しかしこれは実装が不完全で一部のキーがちゃんと判定されなかったりした。が、マルチプラットフォーム・マルチブラウザで検証するような気力はないし、そんなことしても無駄になるのは目に見えているのでやる気はおきない。
KeyBoardEvent に key というプロパティが DOM Level 3 Events ではできることになっていて、これは Enter キーの場合 "Enter" という文字列が入り、物理的なキー位置(ということになっている謎の数値)ではなく、論理的なキーを表現するということになっている。が、全てのブラウザで同じように実装されているとはいえない。
ということで KeyBoardEvent.key には polyfill をつかおう。
https://github.com/inexorabletash/polyfill/blob/master/keyboard.js
を読みこむだけでいい。完璧ではないがおそらく現時点で一番まともだと思う。このファイルにはライセンスが書いてないが polyfill 全体で Public Domain となっており適当に扱っても問題ない。
KeyBoardEvent.key は modifierKey (シフトキーとか) の状態は当然含んでいないので、単に
if (e.key === 'Enter') {
} で判定してしまうと、Shift+Enter や Alt+Enter なども同じもの扱いになってしまう。かといって
if (e.shiftKey && e.key === 'Enter') {
} else
if (e.altKey && e.key === 'Enter') {
} else
if (!e.shiftKey && !e.altKey && e.key === 'Enter') {
} とか全部書くのは見通しが悪い。
ということでしかたなしに
var key = (e.altKey?"Alt-":"")+(e.ctrlKey?"Control-":"")+(e.metaKey?"Meta-":"")+(e.shiftKey?"Shift-":"")+e.key;
みたいなのを1行書いて modifier key のプリフィックスをつけておくとやはり楽になる
if (key === 'Shift-Enter') {
} else
if (key === 'Alt-Enter') {
} else
if (key === 'Enter') {
} そろそろ HTTPS でしか使えない新機能なんかを使いたくなるので、すこしずつノウハウを溜めようという気持ちはあります。
ググって出てくるコマンドだと対話的インターフェイスでどうでもいい情報を入力する必要があってダルいので一発で自己証明書つくれるようにします。
#!/bin/sh cd dev CN=localhost openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Kyoto/L=Kyoto/O=Example/CN=$CN" openssl x509 -req -days 1024 -in server.csr -signkey server.key -out server.crt rm server.csr
server.key と server.crt を使って HTTPS サーバを立てます。
HTTP2 は一応暗号化はオプションということになってるようだが (H2C/HTTP2 Over TCP)、実際の実装では TLS に乗っているものしかないので必然的に HTTPS でしか使えない。
node の http.Server / https.Server を使っている場合、Server のインスタンス化コードを替えるだけで HTTP2 にできる (インターフェイスが一緒)
コンストラクタに server.key と server.crt を指定するだけ。
localhost だけでの開発ならいいが、LAN 内のスマートフォンなどから HTTPS な開発環境にアクセスしようと思うと、IP アドレス指定してもアクセスできない。Chrome の場合、ERR_CONNECTION_CLOSED (This webpage is not available) になる。
どうやらホスト名でアクセスしないとブラウザ側で強制的に接続を切るようで、どうしようもない。
ということで、一旦 LAN 内に DNS サーバを立てて該当コンピュータを名前でひけるようにする必要がある。(mDNS でいけないかと思ったけどダメだった)
node で DNS サーバを書ける実装もある (node-dns (native-dns)) のでこれを使えばとりあえず簡単に書ける。
/etc/hosts 形式を読んで A レコード返すだけのは雑に書いた。
立てた HTTPS サーバと同じマシン上で良いので、port 53 で起動する。sudo が必要。
端末側でもこの DNS サーバを参照する必要がある。
Android では Settings → Wi-Fi → (接続中のネットワーク名を長押し) → Modify network とすすんで、Show advanced options にチェックを入れ、IP settings を Static に変え、DNS 1 にマシンのIP Addressを指定すれば反映される。
またはルータの設定を書き変えて DHCP 経由で通知する DNS サーバを変えてもいいけど、これはこれで面倒。
link rel="import" によるロードはやはりちょっと時間がかかる。Polymer の場合どうしてもインポート数が増えるのでなんとかしたい。
もちろん vulcanize すれば import 自体は解決するが、created/attached まわりの処理もチリも積もればという感じで、なかなか時間がかかるので、根本的解決にならない。
特に appmanifest によってスタンドアロンアプリ表示させている場合、ロードまでの間完全に真っ白の画面になり、プログレスバーも出ないのでかなり残念なことになる。
ということで、一旦ローディング画面を挟みたい。
HTML Imports はポリフィルされていない場合ブロックする (Chrome にしかネイティブ実装されてないから Chrome だけ)。インポート先がインポートしている場合再帰的にインポートするので、依存全部インポートが終わるまで表示が完全にブロックし、head内でインポートしていると画面描画が全く走らない。
Chrome の場合 first paint が走るまで現在表示中の内容を消さないので、リロードした場合特に「全く操作はできないのに表示はされている」状態になって気持ちが悪い。
なので、まずはインポートなしの状態ないし、最低限必要なものだけをインポートしてから、ロード画面を表示する。
link要素のloadイベントでひとつのインポートの完了はわかるが、再帰的な全てのリクエストのプログレスをとることができない。
どうしようもない?ぽいので、intermidate なローディングプログレス表示するしかない。
CSS でアニメーションさせるのが現状では一番マシっぽい。
<div class='loading'></div>
<my-app></my-app>
<script>
requestAnimationFrame(function () {
var link = document.createElement('link');
link.rel = "import";
link.href = "src/app.html"; // my-app の定義
link.addEventListener('load', function () {
var loading = document.querySelector('.loading');
loading.parentNode.removeChild(loading);
});
document.body.appendChild(link);
});
</script> link rel="import" は作って挿入してもちゃんと動いてくれるのでこれで良い。polyfill もちゃんと動いててうまく動く。
load イベントは再帰的なロードが全部終わってから発火するようになっている。
HTTP2 化してもカスタムエレメントの初期化処理はなくならないので、大量のカスタムエレメントを使う場合なんらかのローディング表示が必要ではないかという気がする。
appmanifest によるスタンドアロンアプリ化ではコンテナ(ブラウザ)側でそのうちちゃんとローディング出せるようになりそう。