Webページでユーザが読んでいるセクションのタイトルをヘッダーに表示したい(React)

はじめに

お久しぶりです。ネットワークデザインスタジオM2の及川です。
今回のテーマは、「Webページでユーザが読んでいるセクションのタイトルをヘッダーに表示したい(React)」です。
Webページ制作時に試行錯誤した結果たどり着いたコードを残したいと思います。開発はReact(Next.js)を使用しています。
また、公式があまり推奨していないものも使用しています。全く良いコードではないかと思います。「とりあえず動いた!」記録になりますのでご了承ください。

対象読者

  • HTML, CSS, JSがわかる
  • Reactはある程度わかる(詳しく触れません)
  • ヘッダー等にユーザが読んでいるセクションのタイトルを表示したい または、目次でユーザが読んでいるセクション箇所(現在地)を目立たせたい

想定されるWebページ

本実装が必要になったのは、以下のようなWebページ作成時です。

想定されるWebページの例
ヘッダーにはユーザの現在のセクションタイトルが表示されていて、そこをクリックすると目次がでてくるようなWebページや、目次がサイドバーとして表示されていて、ユーザの現在のセクションタイトルが目立つように表示されているようなWebページです。
学習系のサイトやブログなどで見ることが多いかと思います。
今回は目次の機能は省略し、ヘッダーにユーザの読んでいるセクションのタイトルを表示する、以下のような簡単なWebページを作成した時のコードについて書きたいと思います。

ざっくりまとめると、ステート関数でヘッダー内の文字を管理しようとしたら要らない再描画が起こってしまったのでrefを使って管理した!という内容です。

開発環境

  • React 18.2.0
  • React Intersection Observer
  • Tailwind CSS 3.3.2
  • Type Script 4.9.5

おおまかな構造

  • index.tsx
    • App.tsx
      • Headerコンポーネント
        ヘッダー内の文字列を指定する関数(handleHeaderText)を用意する。親(App.tsx)からも使用できるようにする。
      • MainContentsコンポーネント
        • Sectionコンポーネント
          React Intersection Observerでスクロールを管理する。セクションに入った/セクションから出た時に、Headerコンポーネント内で用意したhandleHeaderTextを用いてヘッダーの文字列を変更する。

最終的なコード

React Intersection Observerが必要となるため、インストールしてあります。

npm install react-intersection-observer

index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import { App } from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

こちらに関してはよくあるサンプルアプリケーションと同様のため、スキップします。

App.tsx

import { useRef } from "react";

import { Header } from "./components/Header";
import { MainContents } from "./components/MainContents";

const data = [
  {
    id: "apple",
    label: "はじめに",
    body: "顔は処の病気聴衆らからゴーシュが過ぎ小太鼓たた。ではいきなりくたくたましでにとって舞台でしまし。まじめたたんましもなくところが楽長の愉快げの所へはにわかに元気でうが、みんなまで東をしれものんまし。わからすぎ何も血を悪いならので途中の楽長のゴーシュ人にし第何先生がいのまねが叩くていんまし。",
  },
  {
    id: "banana",
    label: "第1章",
    body: "係りは楽隊をたいへんにやめが棒に孔のようがやってホールを見てどんなに皿を仕上げてやりだ。ぐるぐるおもわず風に小節がしんなら。みんなちょっとにセロにあけてむしをなっただ。一つにすましますなら。 「キャベジからくわえだろ。壁、やつをゴーシュ。入れ。」そこはたくさんのときのこれから前のときをきますなら。手は枝からすゴーシュをいっが孔で壁へしからどうか半分ひるられるますうちが出たで。まるでおねがいきいて、してなおりから来たて気持ちがでは拍子をそのまま時きいだまし。「ドアき。たばこに考えだ。いろわ。おれは何に狸を思えからじゃやめ音楽は黒い方たながらね。」それは愉快そうがひとべゴーシュドアにしとだ舞台のセロを弾いて弾いと落ちついててるです。かぶれははせてゴーシュに聞えるたな。誰もすっかりゴーシュは悪いどころでてホールもいきなり悪いのましまし。「こんどの半分の中から。なっ。」きみはいきなり下げなな。",
  },
  {
    id: "orange",
    label: "第2章",
    body: "マッチも下からあわせてひとつない。では一生けん命はぜひなるたらた。うるさい拍手だっと合わて行っからかっこうで怒るようた楽長をしてするとのそのそ下を番目叫びだた。またかとおっかさんはてやっとなっましたてありがたいものをは一生けん命は形のおいでたです。先生はあなたをさっきまし子のままおれにくわえないようになあタクトかっこうを口へおどすてそれかどなりんが睡ててましまし。「するとぎっしり一生けん命のあと。する。」あと許して飛びだしたかとはいりてなぜゴーシュを狸にどうぞなってこどもいじめなな。「愉快た。そのままきかせて行っまし。",
  },
  {
    id: "grape",
    label: "第3章",
    body: "こんなんは勢のゴーシュだんない。君がこのうまくつかれるたんが。係り。せいせいじゃあぱたっと狸一ぺんも広くのますなあ。ゴーシュをドレミファをやっていぼくらがこのかっこう虫かっかたりあと屋のホールなんての頭ゴーシュを結んてくださいたすっかりみんなのちがいもこう出ことな。用口さん。",
  },
  {
    id: "peach",
    label: "おわりに",
    body: "晩は寄りのかっか頭たちを曲がつけ楽長ないた。またまたまっ黒たでて風車ですなら。元気ましましもんたはだでは先生のまじめ汁のままへはすっかり生意気ただて、ぼくほど狸が出られるんましまし。もっすぎそれも扉をいいたとたくさんの扉の狩屋を聞える第三ろ汁のきょろきょろを見からいるなくだ。巻は毎日はいっでいだろ。本気は万落ち糸のようから聞いてしまうた。音もかっこうばかやどこと見ていで。セロはひもへあんまりとねむりからかっこうをいちどのようをあわてとゴーシュからわかってじっと子で叩くからやるまい。ぼろぼろじつにゴーシュを狸がききだた。みんなまたに呆気に困るて向うを来ですまし。ゴーシュが云いました。「こどもが出だ。棒、みんなをゴーシュ。叫び。」これはたくさんのままのすこしこんどのときをあれたます。頭はタクトにお晩をはいって野ねずみを狸が叫びてさっさとこんどあわてられるなかっ所へ云いたた。よほど病気ありて、こぼして見るてくださいんてあとをまたみみずくをいつも日ひいたませ。「壁い。からだを居りた。見るな。",
  },
];

type HeaderComponentType = {
  handleHeaderText: () => void;
};

export const App = () => {
  const headerRef = useRef<HeaderComponentType>(null);

  const headerTextRef = useRef<{ id: string; label: string }>({
    id: data[0].id,
    label: data[0].label,
  });

  const handleHeaderText = () => {
    if (headerRef.current) {
      headerRef.current.handleHeaderText();
    }
  };

  return (
    <>
      <Header headerTextRef={headerTextRef} ref={headerRef} />
      <MainContents
        data={data}
        headerTextRef={headerTextRef}
        handleHeaderText={handleHeaderText}
      />
    </>
  );
};

ここではまず、dataという変数名に対して本文を用意しています。セクションごとに、id、label(タイトル)、bodyを用意しています。
続いて、Headerコンポーネントで用意した関数を使えるように、HeaderコンポーネントへheaderRefを渡します。また、Headerコンポーネント内で描画する文字列をheaderTextRefで渡します。
行いたいことは、MainContents内で新しいセクションに入ったことが検知された時に、新しいセクションのタイトルをHeaderコンポーネントに渡すことです。
当初、ステート関数でheaderText, setHeaderTextを用意してそれぞれのコンポーネントに渡していたのですがうまくいきませんでした。ステート関数で管理した場合、HeaderだけでなくMainContentsも再描画されてしまうからです。今回のサンプルWebページでは文字のみのため特段問題ないのですが、MainContents内に画像や動画が入っていた場合、スクロールしてセクションを跨ぐたびに再描画される…という事態になってしまいます。それを防ぐためにrefで管理を行うことにしました。

Header.tsx

import { forwardRef, useImperativeHandle, useState } from "react";

type HeaderText = {
  id: string;
  label: string;
};

type Props = {
  headerTextRef: React.MutableRefObject<HeaderText>;
};

export const Header = forwardRef(({ headerTextRef }: Props, ref) => {
  const [headerText, setHeaderText] = useState<string>(
    headerTextRef.current.label
  );

  const handleHeaderText = () => {
    setHeaderText(headerTextRef.current.label);
  };

  useImperativeHandle(ref, () => {
    return {
      handleHeaderText: handleHeaderText,
    };
  });

  return (
    <header className="sticky top-0 h-20 flex items-center justify-center bg-slate-600">
      <p className="h-fit text-l text-center text-white font-bold">
        {headerText}
      </p>
    </header>
  );
});

ここでは、forwardRefを使用してhandleHeaderTextを親コンポーネントから使えるようにしています。ヘッダー内の文字列はここではセットしていません。

MainContents.tsx

import { Section } from "./Section";

type HeaderText = {
  id: string;
  label: string;
};

type Data = {
  id: string;
  label: string;
  body: string;
};

type Props = {
  headerTextRef: React.MutableRefObject<HeaderText>;
  data: Data[];
  handleHeaderText: () => void;
};

export const MainContents = ({
  headerTextRef,
  data,
  handleHeaderText,
}: Props) => {
  return (
    <div className="max-w-md py-10 flex flex-col gap-20 mx-auto mb-96">
      {data.map((item) => {
        return (
          <Section
            item={item}
            headerTextRef={headerTextRef}
            handleHeaderText={handleHeaderText}
            key={item.id}
          />
        );
      })}
    </div>
  );
};

ここはSectionコンポーネントを並べているだけなので説明を省きます。

Section.tsx

import React, { useEffect, useRef } from "react";

type HeaderText = {
  id: string;
  label: string;
};

type Item = {
  id: string;
  label: string;
  body: string;
};

type Props = {
  headerTextRef: React.MutableRefObject<HeaderText>;
  item: Item;
  handleHeaderText: () => void;
};

export const Section = ({
  headerTextRef,
  item,
  handleHeaderText,
}: Props) => {
  const ref = useRef<HTMLElement>(null);
  
  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting && entry.boundingClientRect.top < 90) {
            if (
              entry.target.querySelector("h2") === null ||
              entry.target.querySelector("h2")!.textContent === null
            )
              return;
            headerTextRef.current = {
              id: entry.target.id,
              label: entry.target.querySelector("h2")!.textContent!,
            };
            handleHeaderText();
          }
        });
      },
      {
        threshold: [0, 1],
        rootMargin: "-90px 0px -90px 0px",
      }
    );

    if (!ref.current) {
      return;
    }
    observer.observe(ref.current);

    return () => {
      if (ref.current) {
        observer.unobserve(ref.current);
      }
    };
  }, []);

  return (
    <section ref={ref}>
      <h2 className="p-4 mb-4 text-2xl font-bold bg-slate-200">{item.label}</h2>
      <p className="leading-7">{item.body}</p>
    </section>
  );
};

ここでは、React Intersection Observerを使って、スクロールを監視しています。画面内に新しいセクションが入ってきた場合、Header.tsx -> App.tsx -> MainContents.tsx -> Section.tsxと渡ってきたhandleHeaderText関数によってヘッダー内の文字列を変更しています。

おわりに

今回記載したコードは推奨されていないものを使っていたり、ややバケツリレーのような形になっていたり、よろしくないコードかと思います。今後、より良いコードへアップデートしていきたいと思います。

Flutter入門時に確認したいまとめ集

目次

はじめに

こんにちは,光岡です. 最近スマホアプリケーションを作りたくなり,Flutterを触り始めました! Flutterとは,一つのソースコードiOSAndroidのアプリを開発することができる「クロスプラットフォーム」(マルチプラットフォーム)に位置づけられるGoogleが開発したフレームワークのことです.Dartという言語を利用して開発します.

以前までは,IOSアプリはSwift,AndroidアプリはKotlinなどのプログラミング言語が主流で,両方のアプリを作りたい場合は,それぞれで開発する必要がありましたが,Flutterはその課題を解消してくれます!

便利なFlutterですが,参考になる書籍や記事が他の言語に比べるとまだまだ少ないかな?という印象があり,日ごろバックエンド開発ばかりしている私にとって,何だかよく分からんとなっていました.

そこで本記事では,Flutter入門する際に,ざっくりでも把握しておくと後々スムーズに開発できるであろう機能などについてご紹介していきたいと思います!

対象読者

  • Flutterのドキュメント等をざっと見た方(本記事では網羅的に紹介しないため)
  • チュートリアルなどやってみたものの,何となくしかまだ理解できていない方

Dartの基礎文法

Dartは静的型付け言語です.dynamic型と呼ばれる特徴的な型を利用して動的型付け言語のようにも扱うことも可能です.

変数宣言

var 変数名 = 値;

or

<型> 変数名 = 値;

定数宣言

const <型> 定数名 = 値;

or 

final <型> 定数名 = 値;

or 

late <型> 定数名 = 値;

最初Flutterでの開発を始めた時,finalが見慣れておらず,何だろう?となりましたが,この書き方で定数を宣言することができます! constfinalの違いは,constはコンパイル時に評価され、finalは実行段階で評価される点です.

また,lateは下記2つの特徴があります.

  • nullを許容しない
  • 遅延評価によるパフォーマンス改善

関数

void hello(String name) {
    print('Hello ${name}!');
}

引数に型の指定をします. voidを使う場合は,返り値なしです.

非同期処理

Future<String> hello() async {
    await Future.delayed(Duration(seconds: 3));
    return "Hello!";
}

非同期処理を実装する場合,Future, async, awaitを利用します. JavaScriptを触ったことがある方は,async, awaitは馴染みあるものかと思います.

Widgetのクラスの使い方について

Widgetとは,UIパーツのことを指します. 私は下記コードのように,Classを作成する際,継承するWidgetクラスに何を使えばよいのか迷うことが多かったので,まとめてみました!

class MyHomePage extends XxxxWidget {
  .
  .
}

StatelessWidget

値の変更をしないときに利用します.

StatefulWidget

値の変更が可能です あまり推奨されておらず,後述のものを使用した方が良いそうです!

ConsumerWidget

RIverpodを利用しているとき,StatelessWidgetではなく,ConsumerWidgetを使います! ほぼ同等のものであり、build メソッドに第2パラメータのrefが存在するかどうかの違いのみです!

class HomeView extends ConsumerWidget {
  const HomeView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // `ref` を使ってプロバイダーを監視する
    final counter = ref.watch(counterProvider);
    return Text('$counter');
  }
}

Provider, RIverpodとは) プロバイダの利用方法

ConsumerStatefulWidget

Riverpodを利用している際,変数 & provider変数の変更が可能です StatefulWidgetとの違いは,ConsumerWidget同様,refが存在するかどうかの違いです!

class HomeView extends ConsumerStatefulWidget {
  const HomeView({Key? key}) : super(key: key);

  @override
  HomeViewState createState() => HomeViewState();
}

class HomeViewState extends ConsumerState<HomeView> {
  @override
  void initState() {
    super.initState();
    //  `ref` は StatefulWidget のすべてのライフサイクルメソッド内で使用可能です。
    ref.read(counterProvider);
  }

  @override
  Widget build(BuildContext context) {
    //  `ref` は build メソッド内で使用することもできます。
    final counter = ref.watch(counterProvider);
    return Text('$counter');
  }
}

HookWidget

Flutter Hooks(UIの状態管理をサポートするライブラリ)を利用しているときに使用します

RiverpodとFlutterHooksの使い分けは下記を目安にすると良いと思います! - グローバルにステート情報を管理したい → Riverpod - 1つのwidgetでステート情報が完結する → Flutter Hooks

HookConsumerWidget

HookWidgetと,ConsumerWidgetの役割の両方を持ちます.

おわりに

他の言語を触っているから何となくコード読めば理解できるけど,いざ開発してみるとスムーズに進まない...と感じている方がいたら,ぜひ一読していただけたら嬉しいです!

参考文献

騒音日記(一)

 この日記は、自分が聞こえた騒音や感じた騒音を記録します。とくに、僕に影響を与えた騒音や感想を記録します。

目次

はじめに

untitled_230813-2 by Samuel YAN (https://openprocessing.org/sketch/1984800)

 こんにちは。アンです。2022年4月から騒音やノイズについての考察と研究を始めました。先日、学校でのM2の中間発表が終わりました。それをきっかけに、今までやったことをちゃんとまとめました。精読した文献、行ったミニ実験、考察した生活のなかでのサウンドスケープ、制作した作品、制作中のWebサイトなどを整理しました。これから来年の最終発表まで、今までやったことを言語化して論文というカタチで書かなければならないです。そして今年の夏休みの計画を立てました。それは、「騒音日記」を書くことです。日常で聴いた音(特に騒音)を言葉に変換して保存したかったのです。そのほか、騒音についての自分の感覚・感想・思いついたことなども残したいです。論文を書くためだけではなく、作品の紹介・解説などにも役に立つと思います。今回のブログには、先週の2日間の日記を公開します。

2023.8.10(木)

聞いた騒音:
 自然:セミの鳴き声
 機械音:冷房の風

感じた騒音:
 時点:午後の13時30分
 場所:スタジオ
 脳のなかにある騒音との戦い:
 脳のなかの雑念(騒音)が多すぎるので、心が落ち着かなかったです。本を読むときも、脳のなかでは関係ないことを考えていました。集中したかったけど、集中できるまで時間がかかることが多いです。それでは、どうすればいいのでしょうか?瞑想する方がいいのかなと思います。瞑想したら、心が落ち着くかもしれません。落ち着かないというか、やる気ができませんでした。前期の期末発表が先週金曜に終わりました。それ以来、ずっとゴロゴロしてきました。研究や作品制作をする気が弱くなっています。そして、色々考えたことを文字に変換して記入したら、脳のなかでのことを整理できるかもしれません。効果があるかどうか、分かりませんが。一応、考えたことを書きました。

 いきなり、なぜ考えたことを書くかというと、外山滋比古さんの本を読んで、ある方法が気になったからです。『思考の整理学』のなかの「とにかく書いてみる」という文章に下記のようなセンテンスがあります[1]:

 原稿に書いたものを推敲する場合でも、黙って読まないで音読すると、考えの乱れているところは、読みつかえるからすぐわかる。声も思考の整理にたいへん役立つのである。
 思考は、なるべく多くのチャンネルをくぐらせた方が、整理が進む。頭の中で考えているだけではうまくまとまらないことが、書いてみると、はっきりしてくる。書きなおすとさらに純化する。ひとに話してみるのもよい。書いたものを声を出して読めば、いっそうよろしい。

 そして、とくに雑念が多いときには、自分の雑念を書いてみたら、脳のなかの整理ができるならいいと考えて、騒音の日記を書こうと決めました。

2023.8.12(土)

聞いた音と気になる音:

 バイト先に行く途中、午前10時40分頃、銀座7丁目銀座中央通りのある交差点で信号機を待っているとき、隣の自動車のクラクションが鳴っていました。あの車に近いところにいた私はびっくりしました。日本では、自動車のクラクションが聞こえることは珍しいことではないでしょうか?九州大学の岩宮さんたちが行った調査により、車のクラクションは日本であまり聞くことのない音であることがわかりました[2]。日本の音環境の全体的印象としては、静か、良好などのイメージです。だから、今回のクラクションに気がつきました。

  • 好きな音楽

 電車に乗るとき、イヤホンで音楽を聞きながら本を読むのが個人的な好みです。基本的に好きな音楽を聴きます。使っているイヤホンはノイキャン機能がないタイプです。今日は、本の内容に集中するまで時間がかかりました。まわりの音や声がある程度聴こえましたが、そうした音声ではなくイヤホンに流れた音楽に注意を惹かれました。何回も繰り返して聞いた好きな曲だから、歌詞を覚えています。本を読んでいるけど、知らずにイヤホンの音楽と一緒に歌えてしまいました。集中力を高めるため、音楽を聴いたけど、逆に、音楽のせいで集中力が続かなかったです。

 この経験で、以前見たある動画の内容が浮かびました。中国のあるグループ(bilibiliでのフォロワー数は1112.5万)が音声と集中力についての実験を行いました。200人を5チームのA、B、C、D、Eにランダムに分け、数学のテストを受けました。チームAは何も聴かない状況でテストを受けました。チームB、C、D、Eはそれぞれ「好きなソング」「軽音楽」「ホワイトノイズ」「落語」を聴きながら受けました。その結果、点数が一番低いチームは好きなソングを聴いたチームBでした。一方、一番高いのは軽音楽を聴いたチームCでした。チームBが聴いた曲は各メンバーの自分が好きな音楽で良いと言われたので、そのなかの97.4%は歌詞があるポップ・ミュージックでした[3]。私の経験と実験の結果は一緒だとびっくりしました。

さいごに

 今回のブログで先週書いた2篇の「騒音日記」を公開しました。これからも、「騒音日記」を引き続き書きます。

参考資料

[1] 外山滋比古, 思考の整理学, ちくま文庫, 1986

[2] 岩宮眞一郎, 音の生態学 音と人間のかかわり, コロナ社, 2000

[3]【何同学】 为了找到专注的秘诀,我们找500人做了个实验..._哔哩哔哩_bilibili

初夏の記憶と『初夏の旅路』

鎌倉での思い出から生まれた作品について

目次

はじめに

 こんにちは。アンです。

 自分のジェネラティブアートの最新作『初夏の旅路』が、2023年6月17日から6月25日(日)まで開催される展覧会『Proof of X - Blockchain As A New Medium For Art -』(THE FACE DAIKANYAMA)で展示されます。今回のブログは、展示作品の『初夏の旅路』についての話です。

初夏の旅路 Traveling in Early Summer #21

Proof of X との縁

 『Proof of X - Blockchain As A New Medium For Art -』という展覧会では、NFTやブロックチェーンなどをテーマとして、世界中の20名のアーティストの作品が展示されています。特別企画として、Tezosブロックチェーン上のジェネラティブアートNFTプラットフォーム「fxhash」と、ジェネラティブアートNFTプロジェクト「KUMALEON」がコラボレーションし、ライブMintイベントを開催しています。そして、10名までのジェネラティブアーティストの公募活動が始まりました。

 募集の締め切りまでの2日間前、fxhashで活躍している日本のアーティストのsakamuraさんから、公募情報を知りました。今までfxhashに出品したことがないので、心配しながら応募しました。これまで、さまざまなイベントに応募して落選した経験が多かったので、今回の応募に選ばれる希望はあまり抱いてなかったです。そのあとの5月16日、KUMAKLEON のToshiさんからの自分が入選したというメールが届きました。本当にすごく嬉しかったです。ここで、本当にToshi さんやProof of Xの皆さんに感謝します。特に、アーティストのsakamuraさんに感謝を申し上げます。あの日に話し合っていなかったら、今回のチャンスを逃していました。

作品作りの裏話

 入選した瞬間、すごく興奮して嬉しかったですが、どんな作品を作ればいいのかという悩みがすぐ来ました。「fxhashではどんな作品が人気があるかな」「新作を作るか、今まで作った作品を調整しようか」「僕の初めてのfxhashでの作品が売れるか」「fxhashでのみんな、どのような作品が好きかなぁ」「3週間ぐらいの期間内で、自分なりの良い作品が生まれるか」などの質問というか不安の心の声が響きました。

 しかし、悩みながら少しでも決めたことがありました。それは、現在の季節の今の自分の気持ちをちゃんと作品に表現しようということです。そして、4年前の2019年の6月に、友達と鎌倉に旅行した記憶が浮かびました。そのとき、長谷寺に行きました。スマホのなかの記念写真を見ながら、長谷寺での日本の庭園、紫陽花が溢れている階段、鯉が泳いでいた池などの思い出が湧いていました。それは確かに、私にとって初めての日本の今の時期つまり初夏の印象です。自分なりの初夏の印象をジェネラティブアートで表現したら良いかもしれないという気持ちで作品を制作しました。

『初夏の旅路』の解説

『初夏の旅路』の制作過程

 今回の作品で描写するのは、俯視の視点から見える日本の初夏の池の風景です。キャンバスの全体で池の一部を表現します。周りに、池を囲む植物を描写します。池のなかには、鯉が泳いているので、水面に波紋が生じます。キャンバスの比率を1:2(w:h)に設定しました。日本の障子や襖の比率に近づけました。3枚以上の襖のような作品を横並びにすると伝統的な屏風のようにも見えます。

4枚の『初夏の旅路』で組み立てた屏風のイメージ図

 今回の作品では「fx(params)」を使っているので、鑑賞者が設定したパラメーターを変えるとすぐに作品の変化が見られます。そのため、鑑賞者がジェネラティブアートの生成する過程に参加することができます。

fx(params)での『初夏の旅路』

 作品には4つのパラメーター(“Seed Number”、“Type of Plants”、“Amount of Fishes”、“Amount of Waves”)を設定しました。“Type of Plants”で植物の種類を選びます。木の葉、あじさい、松葉と草むらの4種類があります。“Amount of Fishes”と“Amount of Waves”で池のなかの鯉と波紋の数を調整できます。この3つを決定し、“Seed Number”で色、各パーツの位置など他の変数にランダムを与えて、描写する池の風景が変わります。

 作品のタイトルについても少し説明します。作品で表現するのは初夏の池の風景だから、「初夏」を使っています。「旅路」という単語を使う理由はいくつかあります。直接的な理由としては、今回の作品が4年前の旅行の記憶から生まれたからです。今回の展覧会のおかげで私のfxhash上の旅が始まります。そのほか、「僕らはまだ 旅の途上にいる」というセンテンスが大好きです。それは好きな作品の『四月は君の嘘』の主人公のセリフです。そして、日本の歌手の藤井風さんの名曲『旅路』も大好きです。「旅」「旅路」「旅の途上にいる」などのイメージや概念がすごく意味深いと思います。人生は旅だと考えています。

さいごに

 新作の『初夏の旅路』について、いろんなことを紹介しました。NFTアート、ジェネラティブアートやメディアアートなどに興味ある方々、ぜひ会場にお越しいただければと思います。

感謝

 Proof of X、KUMALEON、fxhashのみなさんのおかげで、『初夏の旅路』を無事に出品し展示することができました。心から感謝申し上げます。

はじめてのZine作成 NestJSでバックエンド開発に挑戦

目次

はじめに

こんにちは,光岡です. アンさん,及川さんのブログ記事に引き続き,Zine作成についての最後の記事になります. お二人のブログ記事は以下です.

blog.lab.sugimototatsuo.com

blog.lab.sugimototatsuo.com

ネットワークデザインスタジオの大学院生3名で制作した「カラフルなJavascriptであそぼう p5.js | Konva.js | NestJSのノウハウブック」は以下から確認することができます.

techbookfest.org

私は最後の「PART 3 お手軽にアプリ開発ができるNestJSの始め方」を担当しました.今回,NestJSを選んだ理由と取り組んでみて分かったことについてご紹介します.

NestJSを選んだ理由

アンさん,及川さんのブログ記事にも記載ありますが,3人の共通点からJavaScriptのライブラリに関するZine作成が始まりました.

私の場合,Web開発に関しては,ここ最近Go言語を使ったバックエンド開発をメインに行っており,JavaScriptはしばらく触っていませんでした.以前はAWSを使ったインフラ開発にも挑戦しており,色々な分野を担当できるフルスタックエンジニアを目指しています.フロントエンド開発も本腰入れて勉強したいなと考えていました.そのため,当初はReact, NextJSかReact Nativeに挑戦する予定でした.

ですが,Ruby, Go言語でバックエンド開発を経験してきて,この2つとはまた違った特徴を持ったものに挑戦したいなという気持ちもあり,最終的にはNestJSを選択しました.

NestJSとは,Node.jsサーバーサイドアプリケーションを構築するためのフレームワークです.RubyでいうRuby on RailsPHPでいうLaravelにあたると思います.

事前の情報収集で,NestJSの利用は,下記内容についてメリットがあると感じました.

  • Ruby on RailsのようにORMの利用により開発がしやすい
  • TypeScriptを選択することで型付きにできる
  • フロントエンドと言語を一致させることができる

実際に取り組んで,このメリットを感じることができたかなどについてご紹介していきます.

取り組んでみて分かったこと

情報量はまだ多くない

今回は公式ドキュメント,zennの記事などを参考に基本的なCRUDアプリケーションを作成しました.検索して感じたことは,zennなどの素晴らしい記事があるものの,記事数は他のアプリケーションなどに比べるとまだ多くない印象でした.Ruby on Railsは特に記事が多く,私自身もWeb開発を始めた時にたくさんエラーに遭遇し,素晴らしい記事にたくさんお世話になりましたが,もしこの当時の私がNestJSを選択していたら,きっと挫折していただろうなと思います.

これからはRuby on RailsではなくNestJSを選択する

この子見出しは思い切って言い切ってみましたが,そう思うことができるぐらい,私は魅力を感じました! 主な理由は2つです. 1つ目はRuby on Railsの開発速度に近い状態で型を扱えるからです.最近はGo言語を触っているので,型が無いと私は不安になります. 2つ目はPrismaの存在です.今回ORMとしてPrismaを利用しましたが,Ruby on RailsActiveRecordと同様の恩恵を感じました.DBへのクエリの書き方も直感的で,Prisma Studioも便利でした.

先ほど,情報量のデメリットについて触れましたが,この点がもう少し改善されたら,もっと色々な企業さんで利用されるようになるのではと期待しています!

おわりに

今回は担当したNestJSについて,少し紹介してみました. p5.jsによるジェネラティブアート表現・キャンバスライブラリのKonva.js・Web開発のNestJS,何か少しでも興味を持ってもらった方に是非読んでいただけたら幸いです.

はじめてのZine作成 Konva.jsについて書いてみた

目次

はじめに

こんにちは、及川です。前回のアンさんのブログ記事に引き続き、Zine作成についての記事になります。
前回のブログ記事は以下です。 blog.lab.sugimototatsuo.com
ネットワークデザインスタジオの大学院生3名で制作した「カラフルなJavascriptであそぼう p5.js | Konva.js | NestJSのノウハウブック」は以下から詳細を見ることができます。

techbookfest.org

私は、「PART 2 Konva.jsを使った写真デコサイトのつくり⽅」を担当しました。今回は、なぜKonva.jsをハンズオン形式で紹介することにしたのか、また、Zine執筆を振り返って学んだことをまとめたいと思います。

なぜKonva.jsをハンズオン形式で紹介することにしたのか

今回のZine「カラフルなJavascriptであそぼう p5.js | Konva.js | NestJSのノウハウブック」は、3つあるPARTの内容がバラバラです。これはアンさんのブログ記事でも触れられていますが、3人の興味関心にはあまり共通点がなかったためです。そんな中見つけた共通点が「JavaScript」でした。そこで、JavaScriptのライブラリに関するZineを作成することが決まりました。
私は、大学の授業内でJavaScriptを使用したことをきっかけに、オンライン教材や独学で学んできました。最近はもっぱら、JavaScriptの上位互換と言われているTypeScriptを使ってReactやNext.jsを中心に学んでいますが、今回は初心に戻ってJavaScriptを利用した「何か」をテーマに執筆することになりました。

今回私が選んだライブラリ、Konva.jsは、HTML5 2D キャンバスのためのライブラリです。また次のブログで紹介できたらと思いますが、大学学部4年次の卒業制作で大活躍したのがKonva.jsでした。卒業制作を作る際に、Konva.jsのデモ・チュートリアルの豊富さに驚きました。一方で、それぞれのチュートリアルは繋がりがなく、ハンズオン形式で慣れていくタイプの私にはなかなかとっつきづらいとも感じました(Reactなどのチュートリアルがハンズオン形式と認識しています)。もちろん、一長一短あると思うのですが、ハンズオン形式を好む方々にもぜひKonva.jsを気軽に使っていただきたいな、と思い今回の内容ができあがりました。私と同じようにハンズオン形式が好きでKonva.jsに少しでも興味がある方に読んでいただけたら嬉しく思います。

Zine執筆を振り返って

デザイン・コードが固まってからZineを執筆したほうがよいと学んだ
今回のZine執筆では、機能の洗い出し、Figmaでのデザイン作成を行なった後に、コードを書いて、Zineを書いて、コードを書いて、Zineを書いて…というような進め方をしました。理由としては、コードが完成し切ってからZineを執筆すると漏れが出てきそうだと思ったから、また、コード書いている時にふと感じたポイントなどをそのまま原稿に落とし込むことができるのではないかと考えたからです。しかし、1/3程度の執筆を行なったところで、「あれ、もっとコードをこう書いたほうがよかったかな…」「あ、ここ間違えている」「ここのコード、うまく動いてないぞ…?」など、原稿の修正が必要になりました。その時に「やっぱり一度コードを完成させてから、原稿を執筆したほうがよかったかな」と反省しました。
技術書を書くというのは、こんなに大変で工程が多く労力がかかるものなのかと、いつも読ませていただいている技術書の執筆者の方への感謝の思いがいっそう強くなりました。

他者にもわかりやすいコードを再度強く意識した
私は現在、エンジニアとして長期インターンシップに参加させていただいているため、一人でコードを書いていたときよりは「他者にもわかりやすいコード」を意識しているつもりでした。しかし、今回「人に見られる」ことを強く意識してコードを書き進めていると、何度も「あれ、ここでいいんだっけ」「ここだとまとまりがないかな」などと手が止まることがありました。そういった意味では、なかなかチーム開発を行う機会のない学生は、ブログやZineなどで「人に見られる」ことを意識しながらコードを書くことはとても勉強になるのではないかと思いました。

おわりに

初めてのZine作成は、正直計画的とは言えずバタバタしてしまいましたが、無事に完成させることができてホッとしています。
拙い部分も多いかと思いますが、是非読んでいただけたら嬉しいです。

はじめてのZineでクリエイティブコーティングのコード解説に挑戦

目次

はじめに

 こんにちは。アンです。最近研究室の大学院生の3人で『カラフルなJavaScriptであそぼう p5.js / Konva.js / NestJSのノウハウブック』というテック・ジンを頑張って書きました。私たち3人ではじめて書いたZineなので、色々な困難がありましたが、無事に完成しました。自分が担当した部分は、「PART 1 p5.jsでジェネラティブアート表現を高めるコツ」です。また、表紙・各パートの扉のデザインも担当しました。今回のブログで、担当した部分の内容をちょっと触って、工夫したところなどを紹介します。

Zineの表紙

担当したZineの内容について

 今回のZineのタイトルを見ると、「なぜこんなかたちの本になったのか」という疑問が出るかもしれません。その理由と担当した内容をちょっと紹介します。

 計画の段階で話し合ったとき、研究の分野がそれぞれ違う3人の共通点を考えました。その共通点はJavaScriptです。3人それぞれ独自の研究やプログラミング経験のなか、全員がJavaScriptのライブラリを使ったことがあります。そこで、p5.js・Konva.js・NestJSについてそれぞれ書くことにしました。

 自分は2021年10月から、p5.jsを使って毎日書いた作品のコードをオープンに提供するプラットフォームのOpenProcessingで公開しています。今まで600以上の作品を作りました。p5.jsでジェネラティブアート表現について、ある程度の経験を持っています。p5.jsについての入門書はたくさんありますが、今回のZineでは個人的なクセというか、個人的によく使っているコツを紹介したかったです。そのため、「p5.jsでジェネラティブアート表現を高めるコツ」というタイトルで、シャドー・グラデーション・フィルターの3つのコツといくつかの実例を紹介しました。詳しい内容はZineをご覧ください。

 工夫したのは、コードの解説の部分だと思います。自分の作品のコードは基本的にOpenProcessingで公開しています。しかし、コードの詳しい解説は初めてなので、うまくできないところもありました。どうやって説明したら読者のみなさんに理解してもらえるかを考慮しながら、コードの解説文を書きました。1年前の作品の紹介もあるので、古いコードの意味はときどき自分でもよく分からなかったです。しかし、過去のコードをもう1回見て解説するチャンスはあまりないので、今回のZine作りのおかげでもう1回過去の自作を触れることができて良かったです。

表紙のデザイン

「Sheet music」のアウトプットの一例

 表紙デザインの背景は過去の作品の「Sheet music」です。この作品を選んで使った理由は2つあります。1つは、作品自体がカラフルなことです。Zineのタイトルにある「カラフル」のキーワードに似合うと思いました。もう1つは、シンプルなことです。直線・破線と柔らかなグラデーションを組んで背景としてタイトルを邪魔しないと思いました。また、デザインするとき、3人が書いたコードも背景に配置しました。統一感を出すため、各パートの扉のデザインに表紙のタイトルに使った黄・赤・青の3色を使いました。

3つの扉絵

さいごに

 書いたZineについてを少し話しました。p5.jsでジェネラティブアート表現とKonva.js・NestJSに興味ある方、ぜひZineを読んでみてください。