めろたんのアレ

色々書いてくやつ

CSS Houdini をつかってキミだけの最強レイアウトを組み立てよう!

うぇ〜い

昨日は年を忘れるための飲み会、通称「忘年会」に参加していました。 慌てて記事を書いています。*1

この記事は Misoca+弥生+ALTOA Advent Calendar 2018 - Qiita 8日目の記事です。 昨日はt_haraさんの「Kotlinの.isInitialized呼び出しになぜCallableReferenceの指定が必要なのか」でした。

blog.thara.jp

明日は めろたんさん が「なんかがんばります」だそうです。 これは期待できますよ・・・!

去年と同じパターンだ。

CSS Houdini

皆さんがCSSを書くと、なかなかうまくスタイルを当てることができなかったり、そもそもブラウザによっては対応していないことが多くあると思います。

また少し変えただけのはずが、様々な場所がズレたりしてしまいとてもつらいと感じたことが多々あるでしょう。 まるで"魔法"だな。 と思うことも多々あると思います。

みなさんも魔法使いたいですよね?

そこで Houdini というものがあります!

Houdiniで何ができるかって言うと、ざっくり雑に言うとJSでCSSを拡張できます。 すごいですね。

多くの仕様がまだDraftであったりするので、実戦投入は厳しいですが、面白い技術ではありますし、夢があるので紹介しようかな。と思います。

なにができる?

いろいろあるのですが、

  • CSS の値に型を付ける
  • カスタムプロパティを登録する
    • 型の指定や、デフォルト値の設定等ができる
  • CSS を定義する
  • CSSの レイアウト を定義する
  • アニメーションを制御する

などなどができます。

型をつけるとかはクソ便利なのでさっさと実戦で使えるようになるといいなと思っています。

で今回はそれの説明をしても、あまり映えないのでレイアウトを定義するのをやってみましょう。

キミだけの最強のレイアウト作ろう

でこのレイアウトを定義する仕様が CSS Layout API Level 1 になります。

これはほとんどの?ブラウザで動かないので、Chrome Canary で確認します。

Chrome Canaryを起動後 chrome://flags/, chrome://flags/ にアクセスして Experimental Web Platform features を有効にします。

これで使えるようになるはずです。

ではざっとコードをはります。

index.html

<style>
  .container {
    width: 50px;
    height: 50px;
    display: layout(sample-layout);
    padding: 100px;
    border: solid 2px;
  }
</style>
<div class="container">
  <div>左上</div>
  <div>真ん中</div>
  <div>右下</div>
</div>
<script type="text/javascript">
  CSS.layoutWorklet.addModule('layout.js');
</script>

layout.js

registerLayout('sample-layout', class {
  *intrinsicSizes(children, edges, styleMap) {}

  *layout(children, edges, constraints, styleMap, breakToken) {
    const childFragments = yield children.map((child) => {
      return child.layoutNextFragment(constraints);
    });

    childFragments.forEach((fragment, i) => {
      fragment.inlineOffset = constraints.fixedInlineSize * i / childFragments.length;
      fragment.blockOffset = constraints.fixedBlockSize * i / childFragments.length;
    });

    return {
      childFragments
    };
  }
});

CSS Layout API の使用例
バーン

動かすとこんなかんじになります。

スタイルには対して斜めに配置するようなものは書いていませんが、HoudiniのLayout APIを使うとこういう事ができます。

なにやってるのか簡単に説明

CSS.layoutWorklet.addModule というので指定したファイルを Layout Workletスクリプトとして追加されます。
Worklet というのがメインのJS実行環境とは別に実行されるJSで Web Worker と似たものです。(雑)
ですが、スレッドには依存しなかったり等ちょっと違います。(雑)
詳しくは Worklets Level 1 で。

registerLayout で レイアウト名と実際にどうレイアウトするのかを定義したクラスを渡します。 ここで設定したレイアウトを使うには CSSlayout: 設定したレイアウト名; とすると使えます。

intrinsicSizeslayout がジェネレータ関数として定義されている必要があります。 将来的には Promiseになるかも?みたいな感じっぽいですが、今はジェネレータです。

intrinsicSizes でそのレイアウトのサイズを返します。ですが、今回は特に使わないので無視!

layout で小要素をどうレイアウトしていくかを書いていきます。 今回は引数のうち children, constraints をつかってます。

children が小要素ですね。 constrains はそのレイアウトの制約、利用可能なスペースとかが取得できます。

layoutNextFragmentCSSフラグメント を取得します。 CSSフラグメントには inlineOffset, blockOffset 等があります。 inlineOffset で横の位置、 blockOffset で縦の位置を設定できます。

constrainsfixedInlineSize でそのレイアウトが適用される要素の横幅、 fixedBlockSize でそのレイアウトが適用される要素の縦幅が取得できます。

コードを見ると、

childFragments.forEach((fragment, i) => {
  fragment.inlineOffset = constraints.fixedInlineSize * i / childFragments.length;
  fragment.blockOffset = constraints.fixedBlockSize * i / childFragments.length;
});

とあるので、小要素を順に少しずつずらして言ってることがわかりますね。

これでさっきあったようになるわけですね〜〜

わけわかんない?
僕もよくわかない。

気づいた人もいるかもしれませんがこのレイアウトを当ててる要素にはpaddingがあったのですが、どうみても無視されてますね。
このLayout API を使うとそれらも無視することができます。 強いですね。

まとめ

だいぶたのしいですね。あとCSS Houdini ヤバイ(意味深)という感じがしますね!

とりあえず、こんな感じで自作のレイアウトを組み立てられるので、みなさんも自分の手で

「キミだけの最強レイアウトを組み立てよう!!!」

次回予告

明日は、和食@yoshoku さんが 「Numo::NArrayでなにか実装します」とのことです!
きっとすごいなにかが実装されますよ!!!

余談または蛇足

技術書典5雑に 書いて出しました。

techbookfest.org

150部刷って30部くらいしかでなかったのでめちゃくちゃレアですよ! 欲しい人がいたらリプとかDMください…。

twitter.com

こちらまで

*1:去年と同じことしてる…。学ばないやつだ。

人はどこまでいっても繋がっているのだという話

うぇい〜

最近はちょっとした遠出*1をして良かったなぁ(小並感)となっていたりしています。

最近プライベートなことで色々あったので結構前から思っていることと絡めて書こうかなと思っています。

技術的な話は一切無いし、個人的な感情のアレ(エモ)なので、アレです。

人は"何"と"何"をしているのか

多くの方が一日の1/3近く仕事していたり、学校で勉強していたり、子育てや、その他色々していると思います。

僕はなんと仕事をしているのですが、ほとんどの時間をPCに向き合ってカチャカチャしています。

ですが僕はPCと仕事をしているわけでは無いのです。 あくまでPCを使って仕事をしているわけで、何と仕事しているかというと、同僚であったり、上司であったり、お客さんであったり、 つまりは"人"と仕事をしているんですよ。

結構前に「お前は良いよな。パソコンと仕事してるだけでいいから、人とのいざこざがなくてさ。」みたいな事言われてブチ切れたことがありました。

あくまでPCは道具であり、人と仕事しているのだ。

仕事だけではない。普段の生活でもそうだ。ゴミを出したらちゃんと回収される。電気水道ガスがちゃんと届く。荷物が届く。ちゃんとしたサービスを受けられる。

全部他人がいないとどうにもならない。

どこまでいっても人は人と繋がっていて相互に作用して生きていのだ。

ざつまとめ

何をするにも他人とつながっているのだ。

その繋がりには良い効果も悪い効果もある。

どこまでいっても作用しあうなら良い効果を大きくしたいですね。

*1:隣の県とかだから別にそんなに遠くないんだけど

Coinhiveのアレについて思うこと

注意

このブログをご覧になると、閲覧者様の端末のCPUやメモリ等のリソースを使います。
高負荷がかかる可能性は基本的には無いかと思いますが、ご利用なさっている端末のスペックによっては、一時的に端末が重くなったりする可能性があります。
また閲覧者様によっては意図していない挙動をする可能性があります。
ご了承頂ますようよろしくおねがいします。


うぇい

皆さんにリソースを使うことを明記したので、この記事が原因で検挙されることは無いでしょう!

先日例のCoinhiveの事件で思うところが多々あったので、仕事終わってから爆睡してて起きてから眠気眼で point-hive っていうのを作ったものです。

反響がすごくてビビったりしてましたが、PRとかISSUEとか来て面白かったです。

github.com

さて、そもそもこれを作ろうと思った理由なんですが、高木浩光氏のブログに思考実験について書かれていたので、まぁそんなむずくもなければ考えるところもなにもないのでやっとくか。と思ったところからでした。

高木浩光@自宅の日記 - 懸念されていた濫用がついに始まった刑法19章の2「不正指令電磁的記録に関する罪」

「自分のパソコンのCPUを勝手に使われる」ことと「マイニングさせられる」こととが連なって初めて不正なものとなるのであろうか。それぞれ単独では不正でないのに? ここで考えてみたいのは、以下のツイートをする人がいたように、マイニングせず、ただ空転するだけの無限ループを設置したWebサイトの公開は犯罪なのかという思考実験である。

無限ループで無用にCPU負荷を食ってしまうWebサイトは、バグとして従前からあり得たであろう。それを放置していたからといって犯罪になるとは、これまでのインターネット史の中で誰も言っていなかった。仮に今から故意にそのようなサイトを作って公開したら、警察は摘発するつもりなのだろうか。さすがにどんな田舎警察でもそんなことはしないだろう。

これですね。

これにそそのかされて作った!僕に責任は無い!!!って言いたいわけじゃないのであしからず。

で、公開したら前述したとおり意外と反響がすごく、記事でとりあげられていたりしてびっくりしました。

gigazine.net

internet.watch.impress.co.jp

とまぁいろいろ取り上げられていたので、思っていることをガーッと書こうかなーと思い書いています。

Coinhiveの何が"ダメ"なのか?

今回問題になっているCoinhiveですが、なぜ"ダメ"なのでしょうか。

警察庁Twitterで投稿していたのでそれを見てみてみます。

*1

詳細な情報をみるためリンクへ行く

仮想通貨を採掘するツール(マイニングツール)に関する注意喚起

マイニングツールは、パソコンの処理能力を活用し、仮想通貨を得るためのツールです。同ツールが設置されたウェブサイトにアクセスした場合、ウェブサイト運営者が仮想通貨を得るために閲覧者のパソコンの処理能力が利用されることがあります。

そうですね。

マイニングツールを設置することを検討しているウェブサイトの運営者 自身が運営するウェブサイトに設置する場合であっても、マイニングツールを設置していることを閲覧者に対して明示せずにマイニングツールを設置した場合、犯罪になる可能性があります。

なぜ?何罪?どういう罪なんでしょうか?

インターネット利用者 マイニングツールが設置されたウェブサイトにアクセスすることで、パソコンの処理能力が意図せずに使用され、パソコンの動作が遅くなるなどの事象が発生する可能性があります。意図しない状況で急激にCPUの利用率が高くなるなどの事象が発生した場合には、ブラウザを閉じることで事象が収まるときがあります。

意図とはなにか。誰の意図なのか主語がわからない。主語が『利用者』であれば、メインコンテンツ以外に処理能力が使われるのは意図していないのでは?*2
大半のWebサイトはもちろんのこと、この世のアプリケーションの大半は意図していない処理が発生することになるのではないだろうか?
広告はもちろんのこと、例えばPCの起動時に「ようこそ!」とか表示するのなんてなにに処理能力使ってんだよ!起動に全力を尽くせバカ!となるのでは?

とまあ結局なぜ"ダメ"なのかよくわからない。

ここから読み取れるのは「利用者の意図していないところでPC・スマホ等の処理能力を使うと犯罪になる可能性がある。」ということかなと僕はそう読み取った。

いや無理でしょwww

利用者がどういう意図でWebサイトにアクセスしてくるかなんてわかるわけ無いやんw

利用者「そんなアニメーションいらないし、勝手に処理能力つかわれた。警察〜〜〜。検挙してくれ〜〜〜〜⤴」
ってきたら対応すんの?しないよね?

とまあよくわからんのですわ。でもあのページを見るにそういうことしか読み取れないし、それでも結局罪名とかはわからないし…。

ということで例の神奈川県警に問い合わせたのだが、今の段階(2018年06月16日19時)ではまだ返事が来ていない。多分色んな所から問い合わせがきて大変なんだろう。

結果何がダメかわからん。

つまり僕は何もできないのでは?

警察庁に書いてあるものをそのまま受け取ると、「マイニングツール等処理能力を使用することを明示しなければダメ」という感じっぽい。

で、Webサイトはアクセスしたときから処理能力などなどを使うわけです。明示もクソもないし、同意の余地もクソもないんですよ。

クッションページ(処理能力を使うと明示、同意をさせるだけのページ)とかを用意しても、そのクッションページは意図していないので意図していないところで処理能力を使われたとなれば終わりなわけですね。
つまりWeb全般は犯罪の可能性があるということになるわけですねぇ。*3

とまあ僕のようなWeb系のエンジニアはなにも開発できない国*4になってきたなぁという感じがして正直めっちゃ困惑している。

反対というか声をあげている人たちも同じようなことを考えているのだろうと勝手におもっている。

同意云々が問題なのか?

先のpoint-hiveを取り上げてくれた記事のブコメとかに、「同意が無いことが問題なんですよ〜」と書いている人がいたが、本当にそうなのだろうか?

その記事を読むために裏で動いている各処理について同意はしたのか?
何をクリックしたかとか、どれだけそのページに滞在しているのか等をプログラムで収集していることだって全然珍しくない。それについて同意はしたのか?
広告を表示することにも同意したか??その広告を表示するのにも処理能力をつかうぞ??
そもそもその記事を読みたいだけであって他のメニューバーとか、意味のないそれっぽいフリー画像とか、その他諸々を表示・ダウンロードすることにも処理能力を使っているが全部同意してるか????

現状同意もなにもしていないはずなのに、問題視されていない「処理能力の使用」と今回の問題視された「処理能力の使用」にはなんの違いもないはず。*5

なぜCoinhiveだけ問題になる?

まとめ

Coinhiveを擁護したいわけではなく、何が違法なのかをちゃんと明示してほしいだけなのだ。

でないと僕が今後開発するものは逐一同意を取るためのプログラムを書き続けなければいけなくなる。*6

それどころか、一番最初にも書いたが、ブログですら表示するのに処理能力を使うのでそれも書かないといけないし、ツイートだってそうだし、RTやLikeしたときですら相手の端末に通知を行うことで処理能力を使うわけだ。
全部同意させないといけないのか????
それはおかしいよね。と普通なら思うと思うけど、そことCoinhiveのようなスクリプトとの違いは?
重くなるからギルティ*7なら検挙された人の中には重くならないように調整をかけていた人もいたが、それすら検挙されているけどなぜ?
他人の端末の処理能力をつかって利益を得るからギルティなら広告はなんでダメじゃないの?
重いし利益を得るからギルティってなら動画広告も爆死だし、なんかゲームができる広告とかも重くなったりするけどそれはダメじゃないの?

え?なんなの?

というわけで、僕は怒っているんですよ〜という話でした。

*1:このツイートだけ異様に反応が多くて面白いなーと思いました。

*2:というよりそもそも利用者は常に何に処理能力が使われるか気にしているものなの?僕はそんなに気にしてないけど。気にしているのなら、その割には詳しくない人多すぎない?

*3:まあ極論だし、飛躍しすぎってのもわかるが、意図しているかどうかとか同意があるかどうかとかで話されてもそうなるわ。としか。

*4:最初は"なにも開発できない世界"にしていたが日本以外はとくに大丈夫だろと思い"国"にした

*5:そりゃ計算する量が違うとかはあるが、両方共処理能力を使うことには変わりない

*6:その同意を取るプログラムを実行するための、同意をとるプログラムを実行するための、同意をとるための(以下無限ループ

*7:そもそも重くなるかどうかって端末によって違くないですか?うんこみたいなPC使ってたら楽天とかみたら爆発して死ぬんじゃない?

HTMLとCSSだけでミニゲームをつくる

うぇい。

昨日はお酒を飲んで陽気な気分になっていました。

今は厳しい顔をしながら書いています。

今回は Misoca Advent Calendar 2017 の16日目の記事です。

前の記事は

tech.misoca.jp

これでした!

merotan ( @renyamizuno_ ) が、HTML と CSS を使って究極の何かを作ったことについて語ってくれるそうです。

究極の何かを作ったので書きます。

HTMLとCSSだけでどこまで出来るか

HTMLとCSSはすごい表現力を秘めているのは皆さんご存知かと思いますが、 その御蔭でわけわからんと思うことも多々ありますね!

で「HTMLとCSSチューリング完全」という話もあったりする。

hoo89.hatenablog.com

まぁあくまでネタくらいに受け取ったほうが良いと思う。たぶん。

とりあえずそれくらい表現力があるわけなのです。

それで色々すごいものがありまして、例えばこれ。

Pure CSS3 calculator

HTMLとCSSだけで書かれている電卓なんですって。

やばくない?

電卓出来るならなんでも出来るでしょ。

と思ってミニゲームを作りました。

HTMLとCSSミニゲーム

これです!

github.com

マークアップは適当&CSSとかclassの命名規則とかも適当!動けば良いんだよ!()

f:id:renyamizuno:20171216190331p:plain

以下のリンクからであそべます。 スタート後、赤い丸をクリックするゲームです。 左上にポイント、右上に制限時間があります。

https://renyamizuno.github.io/minigame-only-css/

あとiframeでも

スマホだと見れないかも。 HTML見てもらえばわかりますが、JSは一ミリもありません。

どうやってうごいているか

いろいろ説明しないといけないところがあるので、個別に書いていこうと思う。

タイマー

ゲーム画面右上のタイマーについてはどうなっているかというと、

  <div class="mini-game-timer">
    <div class="mini-game-timer__a">
      <div>
        <div>0</div>
        <div>1</div>
        <div>2</div>
      </div>
    </div><div class="mini-game-timer__b">
      <div>
        <div>0</div>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
        <div>6</div>
        <div>7</div>
        <div>8</div>
        <div>9</div>
      </div>
    </div>
  </div>

HTMLはこうなっている。 タイマーで使う数値を全部書いている。

実際にどう数値を動かしているかというと

.mini-game-timer__a, .mini-game-timer__b {
  display: inline-block;
  position:relative;
  overflow: hidden;
  height: 24px;
  width: 12px;
}

.mini-game-timer__a > div, .mini-game-timer__b > div {
  position: absolute;
}

.mini-game-timer__a > div {
  animation: timer-mekuri-a 30s steps(3) 1;
}

.mini-game-timer__b > div {
  animation: timer-mekuri-b 10s steps(10) 3;
}

@keyframes timer-mekuri-a {
  0% { top: -48px; }
  100% { top: 24px; }
}

@keyframes timer-mekuri-b {
  0% { top: -216px; }
  100% { top: 24px; }
}

こんな感じ。 animationをつかって動かしている。

stepsを使うことで、ステップで動かすことが出来るので、それでうまくやっている。

スコア

これの説明が大変。

まず的からかな。

<input id="target1" class="point" type="checkbox">

<!-- .... -->

<label class="target" for="target1"></label>

的の構成はこんな感じ。 labelが実際の的になっている。

.target {
  position: absolute;
  top: calc(50% - 13px);
  left: calc(50% - 13px);
  width: 26px;
  height: 26px;
  background: red;
  border-radius: 50%;
}

.target[for="target1"] {
  animation: target1-animation 5s infinite;
}

#target1:checked ~ .stage--main > [for="target1"] {
  background: blue;
  pointer-events: none;
}

@keyframes target1-animation {
  0% { transform: translate(100px, 50px) }
  50% { transform: translate(50px, 100px) }
  100% { transform: translate(100px, 50px) }
}

それでCSSはこんな感じになっている。

的を画面中心において、animationtransformをつかい位置をずらしている。

またlabelなので、labelforで指定したidの要素と関連付けが出来ることを活かして、checkboxにチェックが付くようになっている。

それでクリックされた(forcheckboxにチェックが入った)labelに関しては、pointer-eventsを使ってクリックが出来ないようにしている。

チェックが入っているかはcheckedという擬似クラスを使うことで確認できる。

それでスコアの表示の部分については、HTMLは大したことないので割愛。

body {
  counter-reset: score;
}

.point:checked {
  counter-increment: score 10;
}

.mini-game-score::before {
  content: "Score: " counter(score);
}

CSSはこのようになっている。

counterを使ってスコアを計算している。

画面の遷移

最初の「スタート」をクリックしてから「おわり」までの画面の遷移についてどうなっているかというと

<input id="game-start" type="checkbox">
<input id="reset" type="reset">
<label class="stage stage--op" for="game-start">スタート</label>
<div class="stage stage--main">....</div>
<label class="stage stage--end" for="reset">...</label>
.stage {
  position: absolute;
  display: block;
  width: 100vw;
  height: 100vh;
}

.stage--op {
  display: flex;
  align-items: center;
  justify-content: center;
}

.stage--main {
  display: none;
}

.stage--end {
  display: none;
  opacity: 0.3;
  background: black;
  color: white;
  font-size: 36px;
}

#game-start:checked ~ .stage--op {
  display: none;
}

#game-start:checked ~ .stage--main {
  display: block;
}

#game-start:checked ~ .stage--end {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  animation: game-end-animation 30s;
}

@keyframes game-end-animation {
  0% { visibility: hidden; z-index: -1; }
  99% { visibility: hidden; z-index: -1; }
  100% { visibility: visible; z-index: 100; }
}

こうなっている。

「スタート」は的と同様の作りになっています。

チェックが入ったらゲームの画面が表示されます。

同時に「おわり」の画面も"表示"されますが、visibilityを使い非表示にしています。 またz-indexを下げてゲームの画面に覆いかぶさらないようにします。

30秒立つと「おわり」の画面をanimationで、z-indexが100になり、またvisibilityで表示するようにします。

「おわり」の画面は的と同様にlabelとなっていて、for<input type="reset">に向けます。

resetは、クリックするとform要素内のinputを初期値に戻します。 これによりスコアはリセットされ、また「スタート」の画面が表示されるようになっています!

まとめ

つかれた。。。

なんだかcounterとかpointer-eventsとかさ、お前らまじでCSSなの?大丈夫?みたいなこと思ったりしたけど、まぁ便利なのでいいんじゃないかな〜(ハナホジ

とりあえず、これぐらいのことは結構普通にできるんやで〜CSSすごいな〜って思いました。

みんなもHTMLとCSSだけで面白いものつくっていこうな!!!!

あしたはえんださんが「日報bot」について書いてくれるそうです!楽しみだな!

"PDCA"を簡単に高速に綺麗に回す方法

うぇ〜〜い

いろいろあったのに更新はなかったんや。

とりあえず今回は、Misoca Advent Calendar 2017 の4日目に参加していて完全に忘却していたのでヒイヒイいいながら書いています。

間に合え!!!

前回の記事はこれでした!

tech.misoca.jp

明日は、 merotan こと @renyamizuno_が「すごーい」何か書いてくれるそうです。楽しみです。

ヒェ...

PDCAを回す

今年を色々振り返ってやはり流行の廃れるスピードがスゴイなぁ(小並感)と思うのですが、今年流行ったものとしてハンドスピナーとかありましたね。

そのなかで、

togetter.com

こういうのがありまして、

今回はこれをウェブでやっていくぞ!!!!!

というやつです。

釣られた人は釣られたクマーして。

プロトタイプ

See the Pen めっちゃPDCAまわしてる by renyamizuno (@renyamizuno) on CodePen.

雑にね。

イメージこんな感じ。

で普通にやるだけだとつまらないので、Web Componentsをやってみる。

あ。ちょうどここに「イヌでもわかるWeb Components」っていう本があるぞ〜⤴

inutetraplus.booth.pm

(興味がある方はポチッとお願いします🙏)

と露骨な宣伝をはさみつつやっていきます。

やった。

PDCA Rotate

ここでみれる。

github.com

コードはここ。

回し方は簡単。

コードはたったの2行。

<link rel="import" href="./components/pdca-rotate.html">
<pdca-rotate rpm="30" rotate-direction="normal"></pdca-rotate>

これだけで最後まで回せます。

簡単!!!!!

rpmを上げることで高速で回せます。

高速!!!!!!

回し続けてもブレることはありません。

綺麗!!!!!!!!

すごい!!!!!!!!!

はい。

早すぎると止まったりしますね。

技術的な話

大したことはしていないのですが、 最初にも書いたとおり、Web Componentsの技術を使っています。

template要素を使ってテンプレートを作り、「回る」だけのコンポーネントを作ます。 components/rotate.htmlがそれです。

同様にPDCA Spinnerのテンプレートを作ります。 さっきのrotateを使い、「PDCA」の各文字の部分と全体を回します。 文字は読めるように、全体の回る向きと反対方向に回すようにしています。 この辺の回る向きとかはCSSCustom Propertyをつかって良い感じにしています。

PDCA Spinnerrpmとかrotate-directionを受け取れるようにして、簡単に回るスピードや向きを設定できるようにしました。

詳しくはコードをみてくれ〜〜〜⤴

ピュアなJSとCSSとHTMLで書いているので、 Web Packする必要も無いし、ビルドもする必要もないし、 ナウいブラウザならよしなに動く(動くとは言っていない)ので、ためしてくれ〜。

動かない場合は多分Chromeじゃないからだと思うので、

github.com

これを使えば良い感じになるぞ⤴

まとめ

  • Web Components最高。
  • PDCAは簡単に高速に綺麗に回せる。
    • しかしWeb上に限る。
  • アドベントカレンダーは前々からちゃんと書いておこうな。

次回はぴーみずこと@mzp氏が「NGK2017Bの報告書く」とのことです!! 乞うご期待!!!!

Web Audio でシンセを作った話

どうもー

最近は暑くて死にそうです。

高山に行ったんですけど、22℃とかでくそ涼しかったです。

www.instagram.com www.instagram.com www.instagram.com www.instagram.com www.instagram.com

小京都だぞ!という感じがありノスタルジーに浸れたり、山の方に行けば綺麗で景色も見れて最高に涼しくて、最高に最高でした。

奥飛騨に別荘を建てて夏は奥飛騨に住みたい…。

そんな気持ちになりました。

はい。

高山には海の日あたりに学生時代の後輩氏達と行ったのですが、ただ遊びに行ったわけじゃなくて、開発合宿しようぜ〜とのことだったので、前々からちょっとやりたかった、 WebAudioをつかってシンセをつくるぞ〜⤴という気持ちを強く持ちながら、結構な時間を観光を楽しんだのでその進捗のNASAを書きます!!!!

Web Audio?

Web Audio API が正しいかな。

詳しくはこちらをどうぞ Web Audio API

まぁざっくりウェッブで音を扱うAPIですね。

音をだすだけじゃなくて、入力とかも扱うことができます。

でまぁもうこれをつかってシンセとかいくらでも作られているんですけど、まぁ作りたかったんです。

ロマンです。ロマン。

成果物〜

github.com

ネーミングセンスがないので、「FXで有り金全部溶かす人の顔」みたいな顔をしながら 「synse」という名前のパッケージをつくりました。

READMEはまだ無い。

でこれを使ったexampleがこちら

github.com

GitHub Pageで見れるようにしてるので良い感じにアクセスするか、 下のiframe内をご確認くだされ〜。

キーボードのa w s e d f t g y h j kをおすことで音がなります。

一応鍵盤通り?な配置で1オクターブが良い感じになるようになってるはずです。

同時に押してもオシレーターが一個しか無いので、単音しかなりません。

和音を鳴らしたいときは、後述するけどがんばれ。

他のいろいろな input は色々いじってもらうとアナログシンセみたいな感じに音が変わるかと思います。

設計思想とか?

そんなたいそれたものではないけど…

一応、あくまで一応、アナログシンセをイメージして作りました。

vco vcf vca とかをモジュールとして提供する感じにしています。
なので、vcoをそのままspeakerにつなぐこともできるし、vco -> vcf -> speakerのようにvcaを飛ばしたりとかもできるようになってる。

今は無いけど、もうちょっとしたらmixer?というか

vco ->  mixer -> vcf ....
vco ->

まぁmixerかな…。なんだろ…。
みたいに感じにn個の音源を混ぜるみたいなのも作ろうと思ってる。

実装的な話

Flow type とか Type Scriptとかを使って型がほしかったけど、開発合宿で2日くらいしかないし、まぁ後にしよーと思って結構ツライなぁとなってた。素直に入れればよかったけど、webpackとかで苦しんでいたので、そんな余裕はなかった。

そのうち Flow typeをいれたいなぁと思っている。

で、vcoとかはAudioNodeっていうクラスを継承させて作っていて、そこで他のAudioNodeとつなげるところは共通化させている。

vcaだけはちょっと特殊で、時間が経過するに連れて音を大きくしたり、小さくしたりみたいなのがあったので、どうしようか迷いに迷って、setTimeOutを使うようになっている。

よくないなぁ…と思いつつ、web上でのkeydownとかのイベントの発火が押しっぱなしだとワンテンポ遅れたりして、音が急にでかくなったり、いきなり消えたりしてわけわからんくなってしまったので、ダサいけどそうなっている。

今でも微妙なときがあるのでカイゼンの余地がある。

またsynseで提供している、keyboardは単音?1音?しか出せないようになってます。和音は出せません。

なぜならアナログシンセを設計思想においているからです。

和音を出したいときは、ナウいシンセのように複数個オシレーターを準備してやればいいかなと思ってます。*1

まぁvcoをn個用意してやればいいですね。

そのうちmixerができるから良い感じにつなげれば完成ですよ〜和音でますよ〜。

ちょっと話がそれましたね。

またkeyboardの実装もだいぶ汚いものになっています。 こちらもvcaと同様にsetTimeOutがあります。理由はvcaと同様です。辛かったし今もツライ。

そんな感じかなー。

色々もやっとしてるところはあるので、良い感じにしていきたいにゃーって思ってます。

あーあとテストとかも一切ないのでうーんってなってるけど、 これどうやってテストするんだ…ってなってる。 音が鳴るとか、ね。*2

まとめ

  • 高山はめっちゃ良いところだった。
  • web audio api 奥が深い。
  • つらいこともありますが、たのしかったです。

はいー

まぁそんなに使うタイミング無いかもしれないですけど、こういうのやっぱりおもしろいなぁーと思いましたまる。

そんなかんじで、ここまで。

またねー。じゃあねー。

*1:本当にそういう実装というか作りになっているかは知らないけど、多分そう。

*2:なんかでweb audio apiをモックして良い感じの値が来てるかどうか。みたいな感じのテストにすればいいのかな?

PostHTMLのプラグインつくったぞーって話

どうも。

いろんなことに夢見て、そのたびに期待をアレされて悲しくなってるめろたんです。

最近はクリエイターズマーケットっていうイベントで購入したテラリウムを見て心を癒やしています。

はい。

今回はPostHTMLプラグインつくったぞーって話を書こうと思います。

PostHTMLって?

と本題に入る前にPostHTMLってなんぞって話なんですが、

github.com

PostHTMLとは、JSHTML/XMLを変換するツールで、HTMLをパースして、ノードツリーを操作するAPIを提供しています。

PostCSS*1HTML版ですね。

これ単体だと、特になにも起きません。

で、色々公開されている、プラグインを使うことで、HTMLを良い感じに変換したりできます。

そのままのっけるけど、

import posthtml from 'posthtml'

const html = `
  <component>
    <title>Super Title</title>
    <text>Awesome Text</text>
  </component>
`

const result = posthtml()
  .use(require('posthtml-custom-elements')())
  .process(html, { sync: true })
  .html

console.log(result)

みたいにすると、

<div class="component">
  <div class="title">Super Title</div>
  <div class="text">Awesome Text</div>
</div>

と変換されてHTMLが返ってくるっていうやつです。 (このposthtml-custom-elementsっていうプラグイン筋悪くね…ってちょっとおもったゾ…)

静的なページを作るんだけど、複数ページつくらないといけなくて、headerとかは共通につくっておきたいなー みたいなのにすごく便利では?って思ったり崎哲夫してました。

今回作ったの

で、今回作ったのはこちらですー

github.com

英語が苦手なフレンズなのでアレ。

それはさておき、何を作ったかというと、

<!DOCTYPE html>
<html>
  <head>    
    <link rel="stylesheet" href="~~~~" >
  </head>
</html>

みたいに書いたときにstylesheetを中に良い感じに展開してほしい、っていうのを作りました。

なんでいるの?とは思うかもしれませんが、HTMLメールとか?あと、AMPで中に書く必要があったりするじゃん?みたいなので、どうしても中に書きたい場合があるんすよ。

っていうので作りました。

実装はどうなってる?

非常に簡単な作りになっているのでぎっよはっぶでみてくれ、みたいなところはあるけど、まぁ軽く。

github.com これを参考にしてつくりました。

const parser = require('posthtml-parser');
const fs = require('fs');
const path = require('path');

module.exports = function(options) {
  const root = options.root || './';
  const encoding = options.encoding || 'utf-8';
  return function posthtmlInclude(tree) {
    tree.match({ tag: 'link', attrs: { expand: 'true', rel: 'stylesheet' } }, function(node) { // ①
      const href = node.attrs.href;
      let content;
      if (href) {
        const src = path.resolve(root, href);
        content = parser(fs.readFileSync(src, encoding)); // ②
      }
      return { // ③
        tag: 'style',
        content: content
      };
    });
    return tree;
  };
};

これが全コードですね。簡単な作りです。

① ノードのマッチ

ここでlinkタグかつrelstylesheetで、expandtrueのときだけ展開する処理を行うようにしています。 全部展開されると困ることもあるでしょうし、任意のやつだけ展開したいことが多くあると思うので、専用の属性を設けました。 本当はdata-~~とかにすべきなのかなぁとかも思ったけど、まぁ変換された後のHTMLが正しければいいと思うし、まぁいいやってなりました。

②選択したファイルのよみこみ

まぁとくに説明することはないですね。hrefで指定されているファイルを読み込むようにしています。 それを展開するためにcontentに保持しています。

③styleで書き出す

で、その①でマッチした所をstyleタグに変換します。 中身は②で取ってきたやつですね。

テッテレ~

完成。

まとめ

もともとはすでにこういうのあるっしょ〜とか思ってたんだけど、無くて*2、期待をアレされて悲しくなってましたが、意外と簡単な作りだったので、自分でできて良かったです(小並感)。

後々になってposthtml-include使えばよかったのでは?とか思ったけど、なんか気持ち悪いし作ってよかったなと思ってます。

今後、これも盛り上がっていくといいなぁとおもいつつ、無いだろうなぁとおもっためろたんでした。

あ、今回作ったやつnpmで公開しているので、興味がある人は使ってみてくだされ〜

www.npmjs.com

チラ裏

ここからは、愚痴等。

で今、AMPのサイトつくろ〜っと思ってこれ無いやんってなったので作ったのですが、そこまでに至る経緯がクソだったので書いとく。

まず最初 Webpack3出たし、Webpackでやろ〜とおもってposthtml-loaderっていうの使おうと思ったんだけど、

github.com

これね

f:id:renyamizuno:20170702001855p:plain

f:id:renyamizuno:20170702001907p:plain

リリースに載ってないバージョンがリリースされてるんすよwwwwww

しかも壊れてるんすよwwwwwwwwwwww*3*4*5

これ特定するのにまじで精神と時間をすり減らしたから訴訟したい(暴挙)。

で諦めて、cliをつかってみようと思ったら、そっちもうまく動かなくて、精神と時間を溶かした人の顔になってた。

結局posthtmlを叩くjsを書いた。

この時の僕の気持ちは最高にアレだった。

頼むから壊れたままにするのはやめてほしい。

そんなアレでした。

とりあえずnpm界隈はこれだから〜みたいな感じになった。

*1:CSSをパースしてASTを吐いてそれを操作するAPIを提供しているJSのやつ。めっちゃ好き。ロゴがイカしてる。 github.com

*2:ちゃんと探せていないだけかもしれない

*3:もしかしたら使い方が違うかもしれないとかそういうやつかもしれないけど、4時間近く色々試したし、loaderのコードに色々差し込んで確認したりしたから確固たる意志をもって書く。僕は間違っていない。

*4:parserを指定できるので、pug(jadeって言われてたやつ)をつかってみよーと思ったら、

だけ出力されてキレてた。

*5:どうも、parserにoptionを渡す前提で作られていないので、optionを受け取る前提で作られているparserにはoptionを受け取るところで、html(というかpug)の文字列が入ってきちゃって、処理すること無く空を返すみたいな感じになってたっぽい。深くは見ていない。