<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Unformed Building</title><link>https://unformedbuilding.com/</link><description><![CDATA[ウェブ制作に関するあれこれと個人的な記録。]]></description><language>ja-JP</language><managingEditor>pnr.matori@gmail.com (matori)</managingEditor><webMaster>pnr.matori@gmail.com (matori)</webMaster><atom:link href="https://unformedbuilding.com/feed/" rel="self" type="application/rss+xml"/><item><title><![CDATA[許可した漢字だけを使うように指摘するtextlintルールを作った]]></title><link>https://unformedbuilding.com/articles/released-textlint-rule-ja-allowed-kanji/</link><description><![CDATA[許可する漢字をコントールできたり、特定パターンの場合は許可できるようなtextlintルールを作りました]]></description><pubDate>Fri, 23 Jun 2023 06:06:49 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/released-textlint-rule-ja-allowed-kanji/</guid><content:encoded><![CDATA[<p>タイトルどおりですが、許可した漢字だけを使うように指摘する<a href="https://github.com/matori/textlint-rule-ja-allowed-kanji">textlint-rule-ja-allowed-kanji</a>というtextlintルールを作りました。</p><p>すでに特定の漢字セットを使うように指摘するtextlintルールはありますが、自分の要望とはちょっと違う感じでした。</p><p>たとえば常用漢字以外は必ずエラーになるというものなので、ユーザーが許可する漢字を増やしたり減らしたりできるようにしたかったのです。</p><p>また、基本的にはエラーになる漢字でも特定の熟語は許可するようにしたかったというのもあります。</p><section><h2>動機</h2><p>もともとはNHK放送文化研究所の『<a href="https://www.nhk.or.jp/bunken/book/irregular/dic_kanji_notation.html">NHK漢字表記辞典</a>』を基準にしたルールがほしかったという事情があります。</p><p>「<a href="https://www.nhk.or.jp/bunken/summary/kotoba/research/024.html">新用字用語辞典の概要まとまる（１） | ことば（放送用語） - ことばの研究 | NHK放送文化研究所</a>」のPDFを見ると分かるように、NHKの基準は常用漢字とは異なっています。<br></p><p>ほかに、<a href="https://www.pressnet.or.jp/publication/book/pdf/shimbun_yogo.pdf">日本新聞協会の新聞用語集（2010年版, PDF）</a>を見ると、新聞常用漢字は常用漢字の一部を使わないようにしたり、特定の熟語の場合は使えるように、などとなっています。<br></p><p>こういった状況に対応できるようなtextlintルールがほしかったのです。</p><p>とはいえ、必要な漢字セットを更新し続けるというのも自分にはできそうになかったので、いくつかの漢字プリセットを用意し、そこから漢字を除外したり追加したりできるようにしました。<br>熟語の対応は、特定パターンの場合は許可するオプションを追加して対応しました。</p></section><section><h2>設定例</h2><p>リポジトリのREADMEにも似たものがありますが、オプションの例を出します。<br>次のコードはtextlintの対象とするテキストです。</p><pre>職権濫用の諜報から得た情報です。
川が氾濫したそうですが、今日のおかずは野菜炒めです。炒飯もあります。

豆を炒るのは明日です。</pre><p>むちゃくちゃな文章ですが気にしないでください。<br>これに対して当ルールを初期状態ままtextlintを使うと次のような結果が得られます。</p><pre><samp>1:6   error  「諜」は許可されていない漢字です。  ja-allowed-kanji
2:22  error  「炒」は許可されていない漢字です。  ja-allowed-kanji
2:27  error  「炒」は許可されていない漢字です。  ja-allowed-kanji
4:3   error  「炒」は許可されていない漢字です。  ja-allowed-kanji
</samp></pre><p>初期状態では常用漢字のみを使うようにしているので、このような結果になります。</p><p>次に、先ほどのNHK漢字表記を参考に、「濫」を「氾濫」のみに限定し、「諜」を許可、「炒」を「炒め」の場合のみ許可する設定です。</p><pre><code class="language-json">{
  "rules": {
    "ja-allowed-kanji": {
      "preset": {
        "regular": true, // 常用漢字のみの場合はpresetごと無指定でもOK
      },
      "exclude": "濫",
      "allowKanji": "諜",
      "allowPatterns": [
        "氾濫",
        "/炒(?=め)/"
      ]
    }
  }
}</code></pre><p>この設定からは次の結果が得られます。</p><pre><samp>1:3   error  「濫」は "氾濫" 以外のパターンでは許可されていない漢字です。        ja-allowed-kanji
2:27  error  「炒」は "/炒(?=め)/" 以外のパターンでは許可されていない漢字です。  ja-allowed-kanji
4:3   error  「炒」は "/炒(?=め)/" 以外のパターンでは許可されていない漢字です。  ja-allowed-kanji</samp></pre></section><p>こういう感じで、ユーザーが用途に合わせて調整できます。<br>許可する漢字を増やせば簡単にエラーを消せるので、そのあたりのバランスはお任せします。</p><p>その他の設定についてはリポジトリのREADMEを参照してください。</p><section><h2>やりたいことはできた</h2><p>ひとまず、自分の要望を満たすルールは完成したので満足しました。<br>同じ要望を持つ方にも使ってもらえたら嬉しいです。</p></section>]]></content:encoded></item><item><title><![CDATA[Googleアナリティクスを外した]]></title><link>https://unformedbuilding.com/articles/dropped-google-analytics/</link><description><![CDATA[Googleアナリティクスによるトラッキングをやめたという報告です。]]></description><pubDate>Mon, 15 May 2023 10:20:03 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/dropped-google-analytics/</guid><content:encoded><![CDATA[<p>Googleアナリティクス4に移行してくださいというメールで思い出したので、トラッキングを外しました。</p><p>理由としては、そもそも1年くらい見ていないし、前回見たときも同じくらい見ていなかったからです。<br>あってもなくても変わらないなという気持ちでいたので、外してしまおうとGA4のアナウンスあたりから考えていました。</p><p>これで当サイトでは1つもJavaScriptが動いていない状態になりました。</p><hr><p>Internet Explorerと旧MS Edgeをサポートするためのコードが残っているので、そのあたりも対応したいところです。</p>]]></content:encoded></item><item><title><![CDATA[RAP HAYABUSAのレバーとボタンを換装した]]></title><link>https://unformedbuilding.com/articles/rap-hayabusa-parts-conversion/</link><description><![CDATA[RAP HAYABUSAのレバーとボタンを三和電子の静音レバーと静音ボタンに換装したのと、コントローラーの話を少し。]]></description><pubDate>Wed, 01 Feb 2023 09:30:07 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/rap-hayabusa-parts-conversion/</guid><content:encoded><![CDATA[<p>PCでSTGをやる際にアーケードスティックとして<a href="https://hori.jp/products/p4/p4_rapvh_hs/">HORIのリアルアーケードPro.V HAYABUSA</a>（通称RAP HAYABUSA）を使っているのですが、どうもレバーの遊び部分の感覚が好きになれませんでした。<br>ボタンの質感は好きなんですが。</p><p>それで、RAPは三和のレバーに簡単に換装できるということで、三和電子製のレバーとボタンを購入。<br>購入は<a href="https://attasa.shop/">ATTASA</a>を使いました。普段の通販はヨドバシなのでヨドバシで買いたかったんですが、欲しいレバーが取り寄せだったので今回は諦めました。</p><p>レバーは静音タイプのJLF-TPRG-8BYT-SK、ボタンも同じく静音タイプのOBSFE-30とOBSFE-24を。</p><figure><figcaption>レバーとボタンを付け替えたところ</figcaption><picture><source media="(min-width: 696px) and (min-resolution: 1.5dppx)" srcset="https://unformedbuilding.com/images/2023/rap-hayabusa-parts-conversion/rap-hayabusa-parts-conversion@2x.jpg"><img alt="RAP HAYABUSAの内部写真。元々のレバーとボタンも映り込んでいる。" height="600" src="https://unformedbuilding.com/images/2023/rap-hayabusa-parts-conversion/rap-hayabusa-parts-conversion.jpg" width="800"></picture></figure><p>交換はピンを外してパーツを入れ替えたらピンを挿し直すだけでしたので簡単でした。<br>どちらかというと、ボタンを外すのに苦労しました。意外と固かったです。<br>念のため、裏蓋をネジ止めする前に動作確認をしましたが、問題ありませんでした。</p><p>使用感ですが、高反発タイプなのもあって少しレバーが重く感じます。<br>とはいえ、たまにゲームセンターで遭遇していためちゃくちゃ重いレバーほどではなく、本当に「少し重くなったな」という印象です。<br>入力感も変わりましたので、しばらく使って慣れる必要がありそうです。</p><p>ボタンはぺっとりとした感触で、HAYABUSA標準のさらっとした質感と比べるとさわり心地は悪くなりました。<br>汗が出てくると指が滑らなくなります。<br>ボタンの高さはまったく気になりませんでした。</p><p>音は本当に静かになりました。<br>標準のレバーは入力に応じてカチカチ、ボタンはパチパチという感じの音が出ていました。<br>やっているゲームが激しくレバーを動かすタイプのものではないので、レバーの音はトントンというレベルに落ち着きました。</p><p>将来的には<a href="https://qanbausa.com/obsidian/">QanbaのObsidian</a>が欲しいのですが、RAPが元気なのでしばらく購入はなさそうです。</p><hr><p>「STGならセイミツ工業のレバー」という根強い説がありますが、わたしはタイトー系列のゲームセンターで遊んでいたことが多いので三和レバーのほうが慣れています。<br>セイミツレバーが嫌いというわけではなく、慣れの問題です。</p><p>昨年格闘ゲームを少し真面目に始めましたが、そちらはパッドでプレイしています。<br>レバーの持ち方の問題なのかコマンド入力がうまくいかないので、昔から格闘ゲームは家庭用をパッドでプレイしています。</p><p>パッドはXbox Eliteコントローラーの初代を使っていましたが、Dパッドの斜め入力ができなくなったので買い換えました。<br>現在は<a href="https://scufgaming.com/int/xbox-instinct-pro-controller">SCUF Instinct Pro</a>を使っています。</p><p>Xbox EliteコントローラーはDパッドが皿タイプで、トリガーの感触も好きなのですが、シリーズ2は不具合報告が多すぎて避けてしまいました。</p><p>先月発表されたばかりの<a href="https://rog.asus.com/controllers/rog-raikiri-pro-model/">ASUSのROG Raikiri Pro</a>も気になっているので、次はこちらが第1候補になると思います。</p>]]></content:encoded></item><item><title><![CDATA[わたしはページ内検索を普通に使いたい]]></title><link>https://unformedbuilding.com/articles/using-find-in-page-without-interference/</link><description><![CDATA[ブラウザーに搭載されているページ内検索が阻害される例]]></description><pubDate>Thu, 19 Jan 2023 05:43:03 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/using-find-in-page-without-interference/</guid><content:encoded><![CDATA[<p><a href="https://unformedbuilding.com/articles/clipped-text-and-search-within-webpage/">以前にも少し書いた</a>のですが、ウェブブラウザーで使えるページ内検索による体験が阻害されるのが本当にストレスで、その例を残しておこうと思います。</p><p>採用側の気持ちも分かりますので、どうなると皆が幸せになるのか分からないという種類のものなので困ったところです。</p><section><h2>省略されたテキスト</h2><p><code>overflow: hidden</code>と<code>text-overflow: ellipsis</code>または<code>-webkit-line-clamp</code>によってテキストが省略された場合、その省略部分がページ内検索にヒットすると非常に探しづらいです。<br>特に、グリッドで区切られたアイテムが複数列・複数行で並んでいる際に顕著です。</p><p>以前の記事のとおり、わたしはYouTubeでよく遭遇します。</p><p>下記のデモは、1000個のアイテムを並べたものです。<br>このうち、「Red Rose」というワードは12個のアイテムに含まれています。<br>デモを開いて「Red Rose」でページ内検索をしてください。</p><ul><li><a href="https://unformedbuilding.com/demo/2023/using-find-in-page-without-interference/grid-line-clamped.html">テキストが省略されたグリッドアイテム</a></li><li><a href="https://unformedbuilding.com/demo/2023/using-find-in-page-without-interference/grid-default.html">テキストの省略のないグリッドアイテム</a></li></ul><p>テキストが省略されたデモでは、2、4、6、12番目にヒットしたアイテムがどこにあるのか判断できないと思います。<br>フォーカスが移動するわけでもありませんので、<code>document.activeElement</code>を使っても判断できません。</p><p>なお、Safariの場合はこの問題に遭遇しません。</p><figure><img alt="スクリーションショット画像：Safariで「テキストが省略されたグリッドアイテム」デモを開き、「Red Rose」でページ内検索をしたときの画面。" src="https://unformedbuilding.com/images/2023/using-find-in-page-without-interference/find-in-page-on-safari.png"></figure><p>スクリーションショット画像は2件目を表示したときのものです。<br>ページ全体が暗くなり、ヒットした部分だけがハイライトされます。</p><p>さらに、ヒットしたテキストが省略された部分であっても、文の途中を省略してすることでヒットしたテキストを表示しています。<br>ヒット部分の1行目の末尾が省略記号になっているのが分かります。</p><p><code>text-overflow</code>の場合はヒットしたテキストの表示はうまくいっていないように見えますが、画面が暗くなってヒットした部分のハイライトは行われますので、どこにヒットしたテキストがあるのかは判断できます。</p></section><section><h2>仮想スクロール</h2><p>仮想スクロールは大量のデータを表示する際に、パフォーマンス向上を目的として使われるものです。</p><p>その原因と仮想スクロールの仕組み上、画面に表示されないアイテムはDOMツリーから取り除かれます。結果として、ページ内検索にヒットしなくなります。</p><p>次のデモは、前述のデモと同じデータを使ったものです。デモを開いて「Red Rose」でページ内検索をしてください。<br>仮想スクロールには<a href="https://www.npmjs.com/package/virtual-scroller">virtual-scroller</a>というライブラリーを使用していますが、これは他のものを使っても同じです。</p><ul><li><a href="https://unformedbuilding.com/demo/2023/using-find-in-page-without-interference/list-virtual-scroll.html">仮想スクロールのリスト</a></li><li><a href="https://unformedbuilding.com/demo/2023/using-find-in-page-without-interference/list-default.html">普通のリスト</a></li></ul><p>仮想スクロールでは、実際に見えている部分とその前後少しに対象ワードが存在する場合にのみページ内検索にヒットします。</p><p>このときもっとも理不尽に感じるのは、上から順にスクロールしながら見ているときです。<br>特定のワードが確実に存在することが分かっているのに、実際にはページ内検索にヒットしないので頑張ってスクロールしながら探さなくてはなりません。</p><p>わたしの場合、この現象はTwitterの検索結果ページで発生します。</p><p>これはユーザー側でどうにかできるものではありませんので、余計に不便です。<br>テキスト省略の場合は、開発者ツールで該当スタイルを削除すればどうにかなりますが、仮想スクロールの場合はそうではありません。</p><p>制作側としては専用の検索フォームを用意するのが解決策となると思います。<br>しかしユーザー側としては、本来は<kbd>Ctrl</kbd>/<kbd>Cmd</kbd>+<kbd>F</kbd>で済むのに、サイトごとにフォームの位置を覚えたり、仮想スクロールかどうかを調査しないといけないのは手間に感じます。</p><p>大量のデータを一気に描画して落ちるパフォーマンスを改善するのは重要だとは思います。<br>使われるか分からないページ内検索よりも、必ず表示されるデータのほうが優先度は高いでしょう。</p></section><section><h2>まとめ</h2><p>最初にも書いたように、「採用するとページ内検索が機能しなくなるが、採用したほうが多くの場合は有用である」という類いのものは非常に悩ましいです。</p><p>ページ内検索は、モバイルブラウザーではアクセスが少し面倒ですので、使われる場面がデスクトップブラウザーより少ないと思われます。<br>画面が小さく、処理能力もPCより劣るモバイルデバイスを考えると、ページ内検索の優先度はさらに下がるでしょう。 <a href="https://github.com/WICG/scroll-to-text-fragment">WICG/scroll-to-text-fragment</a>によると、Android Chromeでページ内検索を使うユーザーは1%もいないということです。</p><p>テキストの省略は機能としてはあってもなくても変わりませんが、デザインの都合や意思決定者の強い要望によって採用されることも多いでしょう。<br>セレクターにページ内検索がヒットしている状態の疑似クラスがあれば解決できそうです。<br>もしくは、各ブラウザーのページ内検索がSafariのようになるかです。</p><p>仮想スクロールについては何も思い浮かびません。<br>ユーザー側としてはおとなしく用意された検索フォームを使うしかないでしょう。<br>Twitterの検索結果ページの場合、さらに検索ワードを追加して検索し直す、という流れになるでしょうか。</p><p><a href="https://html.spec.whatwg.org/multipage/interaction.html#find-in-page">HTML Standard - 6 User interaction - 6.9 Find-in-page</a>を見ると、<code>window.find()</code>という形でAPIが予定されてはいるようです。<br>該当Issue「<a href="https://github.com/whatwg/html/issues/3539">Potentially standardize window.find() · Issue #3539 · whatwg/html</a>」を見ると、議論の経過が分かります。</p><p>現行ブラウザーでも<code>window.find()</code>は使えるのですが、それは非標準なもので、非推奨になっています。</p><p>このAPIによってページ内検索でイベントが発生するようになったり、該当のノードを取得できるようになれば、今回の問題はどちらも解決するかもしれません。<br></p></section>]]></content:encoded></item><item><title><![CDATA[CSS Gridで作られたコンポーネントの列数と行数を知りたい]]></title><link>https://unformedbuilding.com/articles/how-to-know-columns-rows-count-css-grid/</link><description><![CDATA[CSS Gridの自動リピートで配置されている場合に、列数と行数をJavaScriptから知りたい。]]></description><pubDate>Thu, 01 Dec 2022 07:10:06 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/how-to-know-columns-rows-count-css-grid/</guid><content:encoded><![CDATA[<p>タイトルどおりなんですが、<code>repeat(auto-fill, ...)</code>または<code>repeat (auto-fit, ...)</code>が使われているCSS Gridのコンポーネントの、現在の列数（カラム数）と行数（ロウ数）をJavaScriptから知る方法についてです。<br>ただし、すべてのグリッドアイテムは1セル分の大きさであるという前提条件があります。</p><p>はじめはグリッドコンテナーのサイズと、グリッドアイテムのサイズを調べて計算しないといけないのかと考えていましたが、検索したらシンプルな解決法を見つけました。<br>やはり同様の要望を持つ人はいるようで、StackOverflowで質問されており、その回答が分かりやすいものでした。</p><p><a href="https://stackoverflow.com/questions/49506393/how-to-get-count-of-rows-and-columns-in-javascript-for-flexbox-and-grid-layout">html - How to get count of rows and columns in javascript for flexbox and grid layout? - Stack Overflow</a></p><figure><blockquote cite="https://stackoverflow.com/a/66186894"><p>The questions is al little bit older but in case anybody needs this:</p><p>If you are working with CSS-Grid you don't need so much calculation. You can get the current template settings e.g. with</p><pre><code class="language-javascript">getComputedStyle(container).getPropertyValue("grid-template-rows")</code></pre><p>in modern Browsers this returns the actual values, not the values from your css, so you get a string like</p><pre><code class="language-text">250px 250px 250px</code></pre><p>you can than calculate the current number of rows by splitting the string and counting the elements in the resulting array.</p><p>This might work in older IEs as well, I did not test it.</p></blockquote><figcaption><cite><a href="https://stackoverflow.com/a/66186894">「How to get count of rows and columns in javascript for flexbox and grid layout?」についた回答の1つ</a></cite></figcaption></figure><p>自動的に列数が変更されるグリッドでも、上記コードを使えば行のサイズ一覧をテキストで得られる（同様に列数も取れる）ので、複雑な計算は必要ないとのことです。<br>これならシンプルな解決ができそうに見えますので、<a href="https://unformedbuilding.com/demo/2022/how-to-know-columns-rows-count-css-grid/">デモを作って試しました</a>。</p><p>列数を取得するコードは、最初は次のような処理をしていました。</p><pre><code class="language-javascript">const raw = getComputedStyle(element).getPropertyValue("grid-template-columns");
const count = raw.split(" ").length;</code></pre><p>試して分かりましたが、<code>auto-fill</code>の場合はこれでうまくいきます。1行になって右側に空白ができてもアイテム幅はちゃんとデータとして取得されます。<br>しかし、<code>auto-fit</code>の場合、空白を埋める場合に<code>0px</code>の幅が追加されていきます。これはデモの「スタイル値」を見ると分かるでしょう。結果、見た目の列数と異なった結果を得てしまいます。<br>これを回避するには、<code>0px</code>の幅を取り除いてから数えるしかないでしょう。</p><pre><code class="language-javascript">const raw = getComputedStyle(element).getPropertyValue("grid-template-columns");
const count = raw.split(" ").filter(w => w !== "0px").length;</code></pre><p>こんな感じです。<br>これで見た目と同じ列数を取得できました。</p>]]></content:encoded></item><item><title><![CDATA[Project ZomboidのModを作った話と重複アイテムの並べ替え処理]]></title><link>https://unformedbuilding.com/articles/about-project-zomboid-mod-reorder-duplicates-by-condition/</link><description><![CDATA[「Reorder Duplicates by Condition」というProject ZomboidのModを作ったときの話。]]></description><pubDate>Fri, 06 May 2022 07:42:02 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/about-project-zomboid-mod-reorder-duplicates-by-condition/</guid><content:encoded><![CDATA[<p>昨年後半あたりから「<a href="https://projectzomboid.com/">Project Zomboid</a>」というゲームをやっていました。ゲーム自体は2014年に購入して数百時間はプレイしていたのですが、ひさびさに再開したという感じです。</p><p>それはいいのですが、アイテム収集癖のあるわたしはアイテムの管理に苦労していました。<br>このゲームのアイテムはカテゴリーや名前でソートできるのですが、同じ名前のアイテムはスタックされて、その中身はソートできません。<br>耐久値などのパラメーターが存在するアイテムの場合、同じ名前でも状態が異なるのです。<br>拾ったアイテムなどは最初から状態がバラバラなこともあって、雑に突っ込んでいるとアイテムを取り出すときに状態を確認して選び出すという行動を取らなくてはなりません。<br>それが面倒くさくて、重複アイテムを出し入れして並べ替えるというModを作ることにしました。</p><p>アイテムを収納している箱やバッグから、一度プレイヤーキャラクターにアイテムを移し替える必要がある関係上、キャラクターが持っているアイテムは並べ替えられないなどの制限が発生してしまいましたが、どうにかModは完成し、2月27日に公開できました。<br>それから何度かアップデートして、3月12日版でひとまずやりたかったことは終わり、現在に至ります。</p><p><a href="https://steamcommunity.com/sharedfiles/filedetails/?id=2766834021">Steam Workshop::Reorder Duplicates by Condition</a></p><p>ありがたいことに2000人以上にも使っていただいており、作ってよかったと思っています。</p><section><h2>開発中の話</h2><p>初めて<a href="https://www.lua.org/">Lua</a>を書きましたが、とりあえずエラーなく動いているので大丈夫だと思います……というか、基本的に<code>if</code>と<code>for</code>くらいしか使っていません。<br>どちらかというとゲームのAPIのほうが苦戦しました。<br><a href="https://zomboid-javadoc.com/">APIの非公式Javadoc</a>はあるのですが、説明とかがあるわけではないので、それっぽいものを探して試すを繰り返しました。</p></section><section><h2>並べ替え処理の話</h2><p>たとえば「包丁」という武器カテゴリーアイテムが複数ある場合は次のような表示になります。</p><pre>▶ 包丁 (5)</pre><p>これをクリックするとスタックが展開されます。</p><pre>▶ 包丁 (5)
包丁
包丁
包丁
包丁
包丁</pre><p>その際に、耐久値などのバーが表示されますが、パラメーターによってはマウスオーバーでツールチップを表示させなければなりません。</p><p>このゲームの重複アイテムスタックは任意のアイテムを取り出せますが、スタックに突っ込むときは最後にしか入れられません。<br>例えば上記の包丁の場合、3番めのアイテムを取り出すのは問題ありませんが、戻したときは5番目になります。</p><p>Mod作成の場合、収納の中身を並べ替えてデータを書き換えるという処理も可能ですが、若干チート気味なので個人的には避けたく、バニラで可能な動作のみで完結させたかったのです。<br>チートっぽいと感じるのは、アイテムの取り出しや収納にはゲーム内時間が経過しますが、一気に書き換えるとノータイムで並べ替えが完了するからです。</p><p>この最後にしか追加できないという状況で、最少の手順をどうやって考えればいいのかというのが課題でした。<br>一番最初に出したバージョンでは、たとえば耐久値が「低 → 高」の順で並べ替える際に、最低値以外はすべて並べ替えるという処理をしていました。目的は達成できますが、とても無駄が多かったです。</p><p>ちなみにアイテムスタックの中身を並べ替える場合、キャラクターに次の動作を行わせます。<br>これはバニラの状態で手作業でやるものですが、これをModで自動化したいというわけです。</p><ol><li>スタックから任意のアイテムを取り出す（ゲーム内時間が経過）</li><li>取り出したアイテムを元のスタックがある収納に入れる（ゲーム内時間が経過）</li></ol><p>これを耐久値などの、アイテムカテゴリーごとの重要パラメーターを見ながら行います。<br>アイテム数が10未満だと手作業でも大変ではないですが、そもそもアイテムの種類が多いのと、わたしのような収集癖があるプレイヤーは50個以上のスタックがあってもおかしくありません。<br>また、マルチプレイの場合は複数人分のアイテムスタックも存在するでしょう。<br>（Modの説明にはマルチプレイでテストしていないと書いていますが、サーバー機能は使っていないので普通に動くはずです）</p><p>最少手順を考えなければ、先に書いたように最低または最高の状態以外のアイテムを全部並べ替えれば完了です。<br>しかし実際に使ってみると「このキャラクター手際が悪いな」と感じます。</p><p>たとえば次のようなアイテムスタックがあるとします。<br>展開したアイテムに付いている角括弧内の数値は耐久値だと考えてください。</p><pre>▶ 包丁 (5)
包丁 [1]
包丁 [3]
包丁 [10]
包丁 [10]
包丁 [5]</pre><p>このとき、耐久値が低い順に並べ替えるなら、耐久値が<code>10</code>のアイテム2つを取り出して戻せばいいだけです。<br>ところが何も考えていない場合、耐久値が<code>1</code>以外のアイテムを<code>3</code><code>5</code><code>10</code><code>10</code> の順で取り出して戻すことになります。<br>手際が悪いです。</p><p>結局どうしたとかというと、並べ替えるアイテムを選択するためのデータを作成して、それで必要分を選び出すという処理をしました。</p><p>まず、元の並びのアイテムスタックのデータを取り出し、次のように変換します。<br>（アイテムスタックのデータを取り出すのもちょっとややこしいのですがスキップします）。</p><pre><code class="language-lua">{
  {
    condition = 耐久値,
    index = 元の並びのインデックス,
    item = {アイテムのデータテーブル}
  },
  ...
}</code></pre><p>ここでは耐久値ですが、他にも色々なパラメーターを利用しています。それらの値はメソッドで取得するので、この時点で取得して適当なキーに値を入れておきます。<br>次は値ごとにアイテムをまとめます。</p><pre><code class="language-lua">{
  [耐久値] = {
    value = 耐久値,
    last = 該当耐久値が一致する最後のアイテムのインデックス,
    items = {各アイテムのデータテーブル}
  },
  ...
}</code></pre><p>ここまで終わったら、昇順または降順に応じて、上記のテーブルを耐久値で並べ替えます。これは<code>sort</code>を使うだけなので難しくありません。</p><p>問題の並べ替えるべきアイテムのフィルタリングは次のようにしています。</p><pre><code class="language-lua">local function createTransferItems(data, itemsCount)
    local transferItems = {}
    local previousLastIndex = 0
    for index, baseDataItems in ipairs(data) do
        for _, itemData in pairs(baseDataItems.items) do
            if itemData.index &lt; previousLastIndex + 1 then
                if index > 1 then
                    table.insert(transferItems, itemData.item)
                end
            end
        end
        if #transferItems > 1 then
            previousLastIndex = itemsCount
        elseif previousLastIndex &lt; baseDataItems.last then
            previousLastIndex = baseDataItems.last
        end
    end
    return transferItems
end</code></pre><p>引数<code>data</code>には、前述の値ごとにまとめたアイテムのテーブルを渡します。<code>itemsCount</code>はそのままアイテム数です。<br>やっていることですが、たとえば低い順に並べ替える場合、現在の耐久値より低い耐久値のアイテムテーブルの最後のインデックスより前にある現在の耐久値のアイテムは並べ替えるべき、という感じです。</p><p>あとはこのフィルタリングしたデータにそって取り出して戻すという処理をキューに追加するだけです。</p><p>もしかするともっといい方法があるのかもしれませんが、わたしが思いついた方法は以上です。</p><p>ModのソースはGitHubにあるので、興味のある方は見てみてください</p><p><a href="https://github.com/matori/pzmod-reorder-duplicates-by-condition">matori/pzmod-reorder-duplicates-by-condition</a></p></section>]]></content:encoded></item><item><title><![CDATA[vscode-textlintがWindowsで動かなかった原因]]></title><link>https://unformedbuilding.com/articles/vscode-textlint-dit-not-work-on-my-windows/</link><description><![CDATA[vscode-textlintがなぜかWindowsでエラー吐いて動かなかったときにやったこと。]]></description><pubDate>Thu, 28 Apr 2022 10:41:44 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/vscode-textlint-dit-not-work-on-my-windows/</guid><content:encoded><![CDATA[<p>ついこの間、<a href="https://marketplace.visualstudio.com/items?itemName=taichi.vscode-textlint">vscode-textlint</a>がなぜかWindowsマシンでエラーを吐いてまともに動作しないという問題に突き当たっていました。</p><p>エラーの内容はtextlintサーバーが起動できないとか、そういう感じのものでした。</p><p>今のWindowsマシンは昨年に新調したものですが、その前のマシンでは問題なく動いていたため、エクステンションの問題ではないだろうと考えて原因を探すことに。</p><p>結果としてはVS Codeのインストール場所が悪かった、というものでした。</p><p>今回、VS CodeをProgram Filesフォルダーにインストールしていたので、アクセス権限関係の問題だったのでしょう。<br>結局、VS Codeのインストーラーが提示する初期インストールフォルダー（ユーザーフォルダー）にインストールし直したところ、vscode-textlintは問題なく動作しました。</p><p>Program Filesフォルダーの権限をいじればインストールし直さなくてもいいのかもしれませんが、それはそれでなんとなく気持ち悪いので、このまま使おうと思います。</p><p>具体的な内容のある記事でなくて少し申し訳ないですが、メモとして残しおきます。</p>]]></content:encoded></item><item><title><![CDATA[CSS Niteに登壇した]]></title><link>https://unformedbuilding.com/articles/cssnite-2021-11-19/</link><description><![CDATA[CSS Nite「CodeGridから読み解くイマドキのCSS 第二弾」に登壇したときの話。]]></description><pubDate>Tue, 25 Jan 2022 02:49:42 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/cssnite-2021-11-19/</guid><content:encoded><![CDATA[<p>昨年の話になりますが、2021年11月に開催されたCSS Nite「CodeGridから読み解くイマドキのCSS 第二弾」に登壇しました。</p><p>発表タイトルは「今から使える、いつか使える日本語ウェブ文字組みの機能」ということで、主にCSSのテキスト周りの機能について話しました。</p><p>昨今の情勢から、イベントはオンラインで開催されたのですが、オンラインの発表というものは聴衆の視線がないので非常に快適でした。ただ、音声については不安があったので、できるだけはっきりと話すように心がけました。<br>とはいえ、わたしは普段あまり大きな声で話さないので、実際のところどうだったのかは疑問ではあります。</p><p>CSS Niteということで、ひとつのテーマを深く話すというよりも、ある程度の範囲を浅すぎない程度に話すという目標で発表しました。<br>普段ブログや会社のオンラインマガジンで書いているものは前者になりますので、どのあたりまで話せばいいのか、これを言わなくて大丈夫なのか、特定ケースで発生する不具合の紹介はしなくていいのか、そういう悩みがつきまといました。<br>少し広めに、深すぎず浅すぎずに話すというのはかなり難しいものだと実感しました。</p><p>スライドについてですが、デモというか「こういう表現ができますよ」の画像がテキストの画像ですので、本文は少なめにし、伝えたいことは話して伝えるという形にしました。<br>スライド内の本文にたくさん書くと、あとで見たときに何を話していたのか分かりやすいという利点がありますが、スライドはあくまでも補助であってメインは話であるという意識で取り組むのがよいのではないかと考えを改めた結果です。<br>また、オンラインのイベントで参加者がスライドを見る大きさ（ストリーミング動画の再生解像度）が異なるので、スライド自体は簡易な見た目のほうが利点が大きいと思いました。</p><p>当日のスライドは「<a href="https://unformedbuilding.com/slide/cssnite-2021-11-19/">今から使える、いつか使える日本語ウェブ文字組みの機能</a>」です。<br>使用したものは<a href="https://revealjs.com/">reveal.js</a>です。</p><p>最終的にストリーミング動画として配信されるのを前提としていましたので、わたしの環境でちょうどいいサイズに収まるレイアウトで作っています。<br>閲覧環境によってはコンテンツが一画面に収まらないかもしれません。</p><p>登壇は久々でしたが、オンラインということで緊張感はほどほどにできて助かりました。<br>参加者の皆さん、ご清聴ありがとうございました。</p>]]></content:encoded></item><item><title><![CDATA[ARCTIC BioniX P120 A-RGBをラジエーターに設置]]></title><link>https://unformedbuilding.com/articles/install-arctic-bionix-p120-argb-on-a-radiator/</link><description><![CDATA[ARCTIC BioniX P120 A-RGBは30mm厚なので、25mm厚用のネジでは設置できなかった。]]></description><pubDate>Wed, 22 Sep 2021 09:54:21 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/install-arctic-bionix-p120-argb-on-a-radiator/</guid><content:encoded><![CDATA[<p>ARCTICのBioniX P120 A-RGBというファンは厚さが30mmあるので、よくある25mm厚のファン用ネジでは簡易水冷ラジエーターに取り付けることができません。</p><p>結論から言うと、ラジエーターに取り付けるには1 3/8インチ長のネジが必要になります。<br>ネジのサイズ的にはUNC#6-32x1-3/8となると思います。</p><p>ミリネジの場合はどこかの換算表を見て調べてください。</p><p><a href="https://www.amazon.co.jp/dp/B07H7HF4NN">UNC#6-32x1-3/8はamazon.co.jpでも売っています</a>が、ネジ専門ショップで買ったほうが早いかもしれません。</p><p>はじめはどのサイズがいいのか分からず、かなり検索していました。そしてようやくamazon.comのレビューで最適な長さを書いている人を見つけました。</p><figure><blockquote cite="https://www.amazon.com/gp/customer-reviews/R1FQ8722514OXI/"><p>These fans are 30mm not 25mm, so you need 6-32 x35mm radiator screws. You can get these by emailing arctic support and they’ll ship them out to you ASAP. Alternatively try using 6-32 1 1/2inch machine screws with some washers since 1.5” is a bit too long, and they don’t make 1 3/8in screws.</p></blockquote><figcaption><cite><a href="https://www.amazon.com/gp/customer-reviews/R1FQ8722514OXI/">Amazing Corsair alternative</a></cite></figcaption></figure><p>引用している文の前には「短所として、標準のハードウェアでラジエーターに取り付けられない」といったことが書かれています。</p><p>引用部分を読むと、ARCTICに連絡すれば送ってもらえるそうですが、ARCTICはドイツの会社なので届くまで時間がかかります。<br>自分で#6-32x1-1/2ネジをワッシャーと一緒につければいいとも書かれていますが、1.5インチは長すぎるとのこと。<br>ARCTICは1-3/8を作っていないと書かれていますが、送ってもらえるのは1.5インチなのでしょうか。</p><p>ともあれ、このレビューのおかげで#6-32x1-3/8がちょうどいいと分かりました。<br>実際に使用して、問題なく設置できています。</p><p>わたしの場合はケース、ファン、ラジエーターという順番でつけています。<br>ケースはFractal DesignのDefine 7、簡易水冷はSuper FlowerのNEON 360です。</p>]]></content:encoded></item><item><title><![CDATA[display:noneな画像のダウンロードを避けるために]]></title><link>https://unformedbuilding.com/articles/avoid-downloading-images-with-display-none/</link><description><![CDATA[HTMLで読み込む画像はdisplay:noneされていてもダウンロードされるので、それを避けるための方法。]]></description><pubDate>Thu, 27 May 2021 09:44:05 GMT</pubDate><guid isPermaLink="true">https://unformedbuilding.com/articles/avoid-downloading-images-with-display-none/</guid><content:encoded><![CDATA[<p><code>img</code>要素で読み込む画像は、CSSで<code>display: none</code>が指定されていたとしてもダウンロードされることはご存知かと思います。<br>それをどうにかしたいという話です。</p><p>前提として、画面サイズに応じたデザインの変更による画像表示の切り替えを想定しているわけではありません。<br>それにも対応できますが、使いにくいと思います。</p><p>結論から言うと「<code>url()</code>関数を指定した<code>content</code>プロパティをインラインスタイルで指定する」、これだけです。</p><section><h2>なんでこんなことをしたかったのか</h2><p>大量の小さな画像が配置されたウェブページを作っていましたが、それらの大半はユーザーが操作しない限り表示されないUIでした。<br>表示されるかどうか分からない画像をダウンロードさせるのもイマイチな気がして、ダウンロードを遅らせたかったというのが理由です。</p></section><section><h2>通常の<code>img</code>指定</h2><p><a href="https://unformedbuilding.com/demo/2021/avoid-downloading-images-with-display-none/1.html">デモを作ってあります</a>ので、確認してみましょう。<br><code>display: none</code>になっているのは親要素ですが、自身につけても変わりません。</p><pre><code class="language-css">p {
  display: none;
  padding: 10px;
  overflow: auto;
  resize: both;
  background-color: gainsboro;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}</code></pre><pre><code class="language-html">&lt;button id="button">画像を表示する&lt;/button>
&lt;div id="container" class="container">
  &lt;img src="./long-tailed-blue.jpg"
       class="image"
       width="2048"
       height="1536"
       alt="写真：ウラナミシジミ">
&lt;/div>

&lt;script>
const button = document.querySelector('#button');
button.addEventListener('click', function() {
  const container = document.querySelector('#container');
  container.style.display = 'block';
  this.disabled = true;
});
&lt;/script></code></pre><p>デモページで開発者ツールを開き、ネットワークパネルを見てもらうと分かるように、ページを開いた時点で画像がダウンロードされています。<br>これを、ボタンが押下されて<code>.container</code>が<code>display: block</code>になったときにダウンロードさせたいというわけです。</p></section><section><h2>表示されてからダウンロードを開始する</h2><p>ご存知のように、CSSの<code>background-image</code>で指定された背景画像は、対象が<code>display: none</code>になっているとダウンロードされません。<br>これは<code>background-image</code>というより<code>&lt;image></code>型で扱われるリソースがそうなっているのではないかと思うのですが、ちょっとソースが分かりませんでした。CSS Images Moduleあたりかなと思ったんですが、仕様ではなく実装のほうなのかもしれません。</p><p>ともかく、背景画像にすれば<code>display: none</code>のときにダウンロードされないようにはできるのですが、非常に不便です。<br>背景画像を使うということは、該当要素のサイズ指定が必要になりますが、そのためには画像のサイズを知っていなければなりません。</p><p>そこで<code>content</code>プロパティによる要素置換を使います。</p><p><a href="https://unformedbuilding.com/demo/2021/avoid-downloading-images-with-display-none/2.html">デモをご覧ください</a>。<br>画像として扱う要素が<code>img</code>から<code>div</code>になっている以外は同じです。</p><pre><code class="language-html">&lt;div id="container" class="container">
  &lt;div style="content: url(./long-tailed-blue.jpg)"
       class="image">
  &lt;/div>
&lt;/div></code></pre><p>開発者ツールのネットワークパネルを見ると、ボタンを押下して<code>display: none</code>な<code>.cotainer</code>が<code>display: block</code>になって初めて画像がダウンロードされているのが分かります。</p><p><code>.cotainer</code>をリサイズすると、それに合わせて画像になっている<code>div</code>のサイズも変わります。これは<code>img</code>要素で読み込んだときと同じ動作です。</p></section><section><h2>読み上げ対応</h2><p><code>content</code>プロパティに<code>&lt;image></code>型が指定された要素は、アクセシビリティツリー上では画像として扱われます。<br>開発者ツールで確認してみてください。<br>こういう点では問題ありません。</p><p>しかし<code>div</code>には<code>alt</code>属性が使えませんので、代替テキストが指定できません。<br>この問題に対しては、次のように解決されることが望ましいでしょう。</p><pre><code class="language-css">content: url(./long-tailed-blue.jpg) / "写真：ウラナミシジミ"</code></pre><p><code>content</code>プロパティ値の<code>/</code>（スラッシュ）で区切ったあとの文字列は代替テキストとなります。<br>構文的には次のようなものです。（2021年5月17日版 Editor’s Draft）</p><pre><code>normal | none | [ &lt;content-replacement> | &lt;content-list> ] [/ [ &lt;string> | &lt;counter> ]+ ]? </code></pre><p>しかし、2021年5月現在、スラッシュ後の文字列に対応している環境はBlinkエンジンのみです。GeckoやWebkitでは使用できません。</p><p>対応している環境、たとえばGoogle Chromeを使って読み上げてみると、ちゃんと画像であることを伝えてくれます。<br>そうではない環境では、不正なCSSとして<code>content</code>プロパティ自体が無視され、画像すら表示されません。</p><p>対処方法としては、替わりに<code>aria-label</code>を使うことでしょう。</p><pre><code class="language-html">&lt;div style="content: url(./long-tailed-blue.jpg)"
     class="image"
     aria-label="写真：ウラナミシジミ">
&lt;/div></code></pre><p><a href="https://unformedbuilding.com/demo/2021/avoid-downloading-images-with-display-none/3.html">両者を比較するデモをご覧ください</a>。<br>このデモを使って開発者ツールを確認すると、ここまでの説明がわかりやすいかと思います。</p></section><section><h2>問題点</h2><p><code>img</code>要素ではありませんので、<code>width</code>または<code>height</code>属性が使えません。つまり、画像のロードが完了しないとレイアウトが完了しません。<br>ただし、そのような場合は画像のサイズが分かっていることが前提ですので、CSSで指定すればいいでしょう。</p><pre><code class="language-css">.image {
  max-width: 100%;
  height: auto;
}</code></pre><pre><code class="language-html">&lt;div style="
       content: url(./long-tailed-blue.jpg);
       aspect-ratio: 2048 / 1536;
     "
     class="image"
     aria-label="写真：ウラナミシジミ">
&lt;/div></code></pre><p>また、<code>img</code>要素ではないことから、<code>loading</code>属性が使えません。<br>そもそもこの方法を採用するのは特殊なケースかと思いますので、ビューポート外の画像を遅延ロードさせたいなら普通に<code>img</code>要素を使ったほうがいいのではないかと思います。</p><p>レスポンシブ画像はCSSの<code>image-set()</code>関数を使えば解決できそうです。</p><ins datetime="2021-05-28T16:10:05+09:00"><p>これはあくまでも<code>div</code>ですので、コンテキストメニューが画像用のものにはなりません。<br>その点は解決できないでしょう。</p></ins></section><ins datetime="2021-05-28T16:10:05+09:00"><section><h2><code>loading="lazy"</code>じゃ駄目なの？</h2><p>それでもいいです。<br>ただ、現在はWebkitで使えないことは念頭に置いておく必要があるでしょう。<br><a href="https://bugs.webkit.org/show_bug.cgi?id=196698">https://bugs.webkit.org/show_bug.cgi?id=196698</a>がWebkitの対象バグです。</p></section></ins><section><h2>まとめ</h2><p>わたしが使ったケースとしては、タブが20個あるタブUIで、そのコンテンツはリンク集であり、各リンクに小さな画像がついているというものでした。<br>タブUIの中身というものは、表示されるかどうか不明という意味では代表的なものかもしれません。<br>他には<code>details</code>要素でしょうか。</p><p>ほとんどの場合、<code>img</code>要素を使うべきだと思いますが、このような方法もあると知っていれば役に立つことがあるかもしれません。</p></section><ins datetime="2021-05-28T16:10:05+09:00"><aside><h2>2021年5月28日追記</h2><p><a href="https://twitter.com/SaekiTominaga/status/1397914352204668945">@SaekiTominagaさんからご指摘がありました</a>ので、その内容について追加しました。</p></aside></ins>]]></content:encoded></item></channel></rss>
