プログラミング

表現メディアの融和実験

お久しぶりです。
村木瞬です。

しばらくぶりにブログを書こうというか、

書いて発信していかないと!

という意識が芽生えたので、
近況だったり考えていること、これからアクションに移すことなどを
自分の頭の整理も兼ねて書いていこうと思います。

一時期「Advance」というアクション(??)をしていた時があって、
それは何かというと、

毎日Webで面白い表現をして、その実装をブログで解説したり、
製作中に撮ったポッドキャストを埋め込んだりしながら記事を構成する、

記事の発信とWeb制作がセットになった、「×音声」要素があるアクションです。

これは今はもうやめてしまっていて、
というのもAdvanceの延長に「いや、こっちかもしれない」という気付きがあって、そっちに時間を割くようになったからです。

前置きが長くなってしまいましたが、
僕は2年ほど前から、こうやって

「Webでもっと面白いことできるって!!」

と叫び続けている人間なんです。

SWebデザインだったりプログラミングスキルをアプトプットしてポートフォリオにしたい人と、Webを無料で作りたい走り始めの企業をマッチングするサービス「SOSO」を頑張るところから始まり、AdvanceやSpillなど、「Webはもっと面白いコンテンツが増えるはずなんだけどなぁ」と、ずっとウェブウェブ言ってます。

https://soso.gift/

https://note.com/willbeceoofplin/n/n64d0075df1e3

そして、Webデザインの会社で半年ほどコーディングをメインに制作フローを学ばせてもらえたり、普通のクライアントワークをする中で、「お、これは面白いかもしれない!」というテーマに取り組みました。

それが「表現メディアの融和」です。

どうしたら動画と音声を、文字や写真に溶け込ませることができるか。

動画や音声はプラットフォームに留まって盛り上がっていますが、環境も整ってきたので、これからは「記事」でも動画や音声が積極的に活用されていくと思います。

文字と写真が主要メンバーである記事には「スクロール」というインタラクションがあります。動画や音声はリニアなコンテンツであるのに対し、記事はノンリニアです。この「リニアとノンリニアの調和」が一番難しかったのですが、試行錯誤を続けました。ちょっと盛って1年くらいこの「表現メディアの融和」をどうデザインするかに取り組んできました!

探し求めたのは、インタラクティブ動画よりもずっと賢いフォーマット。

そして生まれたのが「Narrative Web」です。

NWからFimsへ

「Narrative Web」だとちょっと長いので、僕はかっこよく「NW」と呼んでいますが、このフォーマットは「文字も写真も動画も音声も入るWebフォーマット」で、結構面白いことができます。

しくみは以下のように、通常であれば最初から最後までがリニアに再生される動画を、内容ごともしくはテロップの数・大きさを基準にガツガツ切っていきます。

特にYouTubeの動画などもスマホを縦にしたまま視聴する人が70%ほどいるそうなので、そう考えるとせっかくの下のスペースがガラ空きになっちゃうし、情報を上1/4くらいに集約することになるので、例えばテロップの容量は限られますし、写真などもめいいっぱいに広げて表示することができません。その上でスマホを縦にして再生されたらもうたまったもんじゃないと。

僕はコーポレートサイトがレスポンシブ対応(スマホ用・タブレット用・PC用と表示を切り分けて最適化すること)されるのがスタンダードなんだから、動画もレスポンシブ化しておかしくないと思ってます。

こんなイメージ

大元の動画素材以外は全部動画の外に出して、グラフィックスで書いてあげればいいのではないかと。結構言われてみれば「いや確かになんで動画に一生懸命詰め込もうとしてたんだろう」ってなりませんか?

これはホームページ、これは記事、これは動画、みたいなそういう境目も「つくる」という観点からすると必要ないんだと思ってます。

だいぶ荒い仕上がりですが、NWを実際に作ってみました。
位置だったり大きさがグシャグシャですが、一応ラップトップでもスマホでもご覧いただけます。
難点は読み込みの遅さ。(サーバーからストリーミング対応させないと厳しいみたい…)

https://fims.tokyo/article

僕はこのNWがだいぶアツい!!と思っていて、と言うのもこのNWを使うと、Webメディアとクリエーションがアップデートされると読んでいるからです。

これに伴って、僕はNWをすべてのクリエイターが活用できる記事の執筆ツール「Fims」を企画しています。(これが今の活動のメイン)

サービス自体開発の「k」も進んでいないのですが、「え、ありそう」と思ってもらえるように、クラウドファンディングから着想を得て、先にホームページを作りました。w
(スピード重視で走っていることもあって、まだラップトップでしかちゃんとみれない状況です。ごめんなさい!※タブレットを横にしてみると微妙に雰囲気は伝わる)

https://fims.tokyo/

こっちの方がまとまってます!(Behance使いたかっただけだがいい感じになった)

https://www.behance.net/gallery/121899859/Fims-Product-Promotion-Video-Official-Website

動画編集をしながら、記事を書きながら、また動画を編集して、といった感じで動画編集と記事の執筆が一元化されたインターフェースで、結構面白そう!(個人的には喉から手が出るほどほしい。一人のクリエイターとして惹かれる。「映画と小説の共創」なんてことも考えています。)

机上の空論を並べていても進まないので、実際に個人で発信をされている方にお話を伺っています。ユーザーインタビューというのでしょうか。その一歩手前ですか。

ストレッチやヨガといったジャンルは動画による解説が必然であることから、
動画編集と記事執筆を同時並行で行うFimsのコンセプトに共感してもらえて、伝えたいことを十分に落とし込める「フォーマット」と「制作フロー」にかなりのニーズがありそうだと。

また、動画編集と記事執筆が一体化したインターフェースを必要としていながら、それが存在しないためにクリエーションに制約を感じるケースもありそうですよね。

料理とかは「音」が大事だそうです。僕は男子校に通う絶賛思春期男子なので料理からはほど遠い位置に住んでいますが、火加減などは写真や言葉で伝えようとするより、そのまま動画を回してしまった方が良さそう。

こんな調子でこのFims、デジタルコンテンツクリエーションのデファクトスタンダードになっちゃうんじゃあないのぉおおおおお!!

と盛り上がっているのが近況です。😂

今後はピッチイベントに出まくるのと、ヒアリングを継続して、FimsのMVPも触れるものを用意してヒアリングを受け入れてくださった方にフィードバックいただけるようにします。

そんなこんなで、駆け足になりましたが、僕はNWというフォーマットに可能性を感じつつ、それをつくれるFimsをローンチするべくせっせと動いている人間になります。

自己紹介と近況報告を兼ねて久しぶりに記事を書きましたが、今後このブログにてものすごい数の発信をしていきます。

というのも、思考まで見える化することが大切なんだということに気付いたからです。

もともと中学生まで小説家を目指していましたから、文字を書き続けることは苦ではありません。

ポッドキャストでしゃべったり記事を書いたり忙しいですが、一応ポッドキャストもそれ用の記事にしてアップするようにします。Twitterで共有していきます!
(ホラァ、だからこういう時にFimsでキュレーションできたらいいのにさぁ..伏線回収..)

Twitterフォローしていただけると!!嬉しい!!!

僕のバックグラウンドに関する詳細はこちらにまとめております!

https://shun-muraki.jp/detail_me/

僕に力を貸してください!!

Fimsをやっていく中で、いろんな方の協力が必要です!

以下に「僕を助けてくださいリスト」を設けましたので、
「ハーン、なかなかおもろいやないか」と思っていただけたら「頑張ってるー?」のノリで、もしくは1ツイート呟くノリで連絡ください!

すぐにお返事します!(早朝と16時以降に!)
それでは、失礼します。

iPhone12が発表されたのでAppleのWebページはScrollMagicとGSAPで実装できるのか検証してみた!

お疲れ様です!

先日10/14に開催されたAppleの製品発表会で噂通りiPhone12が発表されましたね!

今僕はiPhone8を使っているのでホームボタンがないiPhoneを早く持ちたいと思っているのですが、それよりも心躍ったのは「そういえばAppleのWebページって今の自分の知識でもなんとか実装できるんじゃないの!?」という気付き。

AppleのWebデザインはとんでもなく新規性があってクールで毎回驚かされます。
もちろん「デザイン」からあのレベルのものを考えられる自信はまったくありませんが、でも「コーディング」のフェーズに特化して言えば「まだ頑張れるぞ!!」と思い、AppleのWebページを今の自分のナレッジで実装してみようと奮起しましたので、この記事ではそのまとめをしていきます!

「飛ぶように、つぎの次元へ。」

今回は相性の良い高機能なScrollMagicとGSAP3のみを用いてAppleのiPhone12の公式ページの部分部分を実装していきます。(ScrollMagicとGSAPしか使えない)

まずはiPhone12のトップビジュアルから見ていきたいのですが、この特徴はタイトルと画像でスクロールアップする速度が若干異なるパラパックスが使われている点。

Rellax.jsなどのパララックス ライブラリを使っても良いのですが、これらはモバイルで見たときに細かいがたつきが出てしまうので、おすすめはCSSのtransformをうまく使うこと。

<body>
    <div class="white_space"></div>
    <h3 class="h3_progress">ベゼルを削って、スクリーンを広く。</h3>

    <img src="aboutlink.jpg" class="img" alt="" />
    <div class="white_space"></div>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js"
      integrity="sha512-NBLGIjYyAoYAr23l+dmAcUv7TvFj0XrqZoFa4i1o+F2VvF9SrERyMD8BHNnJn1SEGjl1AouBDcCv/q52L3ozBQ=="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rellax/1.9.1/rellax.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/scrollreveal.js/3.0.3/scrollreveal.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
    <script src="javascript/scrolleo.js"></script>
    <script src="javascript/index.js"></script>
  </body>
.h3_progress {
  font-size: 30px;
  text-align: center;
  margin: 0 auto 100px auto;
}

.img {
  width: 600px;
  height: auto;
  display: block;
  margin: auto;
  transform-origin: center;
}
var parallax = gsap.to(".img", {
  y: -150,
});

var scene_parallax = new ScrollMagic.Scene({
  triggerElement: ".h3_progress",
  triggerHook: 0.3,
  duration: 100,
})
  .setTween(parallax)
  .addTo(controller);

「医療に使われるレベルの
ステレンススチール」

こちらに関してはコードをそのまま使っているのと数字をいじったためがたつきが酷くなってます。参考にさせていただいた記事をご覧になった方がいいかもしれないです。。

スクロールに応じて動画が再生される仕組みですが、これは現時点ではどうしても一定のがたつきが目立ってしまうみたいです。

「Scrolleo」というスクリプトを採用しているらしく、これはScrollMagicともGSAPとも無関係ですが、個人的にどんな技術を使っているのか気になったのでご紹介。

参考にさせていただいた(というよりモロそのままじゃないか…)記事のリンクです。↓

https://b.hatena.ne.jp/entry/s/coliss.com/articles/build-websites/operation/javascript/videos-reacting-to-scrolling-inspired-by-apple.html

  <body>
    <div class="white_space"></div>
    <div style="margin-top: 100vh">
      <h3>スクロールに応じた動画の再生!</h3>
      <!-- Video 1 -->
      <video
        id="scrolleo-1"
        width="100%"
        height="100%"
        autobuffer="autobuffer"
        preload="preload"
      >
        <source src="photographer.mp4" />
      </video>
    </div>
    <div class="white_space"></div>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js"
      integrity="sha512-NBLGIjYyAoYAr23l+dmAcUv7TvFj0XrqZoFa4i1o+F2VvF9SrERyMD8BHNnJn1SEGjl1AouBDcCv/q52L3ozBQ=="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rellax/1.9.1/rellax.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/scrollreveal.js/3.0.3/scrollreveal.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
    <script src="javascript/scrolleo.js"></script>
    <script src="javascript/index.js"></script>
  </body>
.white_space {
  width: 100%;
  display: block;
  height: 100vh;
  background-color: #fff;
}
var scrolleo1 = new Scrolleo({
  acceleration: 1, // 1 = instant, 0 = never
  secondsPerScreen: 4, // Defaults to video duration
  additionalOffset: -500, // Positive starts the video later, negative starts earlier. default starts when top of video hits bottom of the screen
  wrapperEl: "#scrolleo-1", // id of the video you want to control
});
scrolleo1.init();

「こんにちは、5G。」

動画がダウンロードされているマークのみSVGが使用されています。

<body>
    <div class="white_space"></div>

    <div class="phone">
      <h3>ダウンロード済み</h3>
      <hr />
      <div class="movie">
        <img src="movie.png" alt="" />
        <h4>グレイハウンド<span>1時間31分・2020</span></h4>
        <div class="svg">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="-20 -20 220 220">
            <defs>
              <style>
                .cls-1 {
                  fill: none;
                }
              </style>
            </defs>
            <g id="レイヤー_2" data-name="レイヤー 2">
              <g id="レイヤー_1-2" data-name="レイヤー 1">
                <rect class="cls-1 apple" width="177" height="177" rx="88.5" />
              </g>
            </g>
          </svg>
        </div>
      </div>
      <div class="movie_under"></div>
    </div>

    <div class="white_space"></div>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js"
      integrity="sha512-NBLGIjYyAoYAr23l+dmAcUv7TvFj0XrqZoFa4i1o+F2VvF9SrERyMD8BHNnJn1SEGjl1AouBDcCv/q52L3ozBQ=="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rellax/1.9.1/rellax.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/scrollreveal.js/3.0.3/scrollreveal.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
    <script src="javascript/scrolleo.js"></script>
    <script src="javascript/index.js"></script>
  </body>
.white_space {
  width: 100%;
  display: block;
  height: 100vh;
  background-color: #000000;
}

.phone {
  width: 650px;
  height: 1500px;
  display: block;
  margin: auto;
  background-color: #000000;
  border: 4px solid #00bfff;
  border-radius: 30px;
  box-shadow: 0 0 30px gray;

  h3 {
    font-size: 40px;
    color: #fff;
    margin: 50px auto 10px 40px;
    font-family: "Noto Sans JP";
  }

  hr {
    background-color: gray;
    opacity: 0.2;
    width: 620px;
    text-align: center;
    margin: 0 auto 50px auto;
  }

  .movie {
    width: 600px;
    height: 180px;
    display: flex;
    margin: auto;
    flex-wrap: nowrap;
    justify-content: space-between;
    align-items: center;
    background-color: transparent;

    img {
      width: 220px;
      height: auto;
    }

    h4 {
      font-size: 15px;
      color: #fff;

      span {
        display: block;
        color: gray;
        font-size: 10px;
      }
    }
    .svg {
      width: 80px;
      height: 80px;
      display: block;
      fill: transparent;

      .apple {
        stroke: #4fa8df;
        stroke-width: 25;
        stroke-dasharray: 600;
        stroke-dashoffset: 600;
      }
    }
  }

  .movie_under {
    width: 600px;
    height: 180px;
    display: flex;
    margin: auto;
    flex-wrap: nowrap;
    justify-content: space-between;
    align-items: center;
    background-color: transparent;
    border-top: 1px solid #484848;
    opacity: 0;
  }
}
var apple = gsap.to(".apple", {
  strokeDashoffset: 0,
});

var scene_apple = new ScrollMagic.Scene({
  triggerElement: ".phone",
  triggerHook: 0.4,
  duration: 400,
})
  .setTween(apple)
  .addTo(controller);

var movie = gsap
  .timeline()
  .from(".movie", {
    scale: 1.7,
    opacity: 0.4,
    y: 300,
  })
  .to(".movie_under", {
    opacity: 1,
  });

var scene_movie = new ScrollMagic.Scene({
  triggerElement: ".phone",
  triggerHook: 0.3,
  duration: 400,
})
  .setTween(movie)
  .addTo(controller);

「ライバルは、
一つ前のiPhoneのチップだけ。」

これを見ていただければわかると思いますが、青い淵はborderで描いているのではなく、ボックスを狭い隙間をとって並べて、全体の背景に複数の円状にグラデーションがかかった画像を置き、先ほど同様transformで絶妙にスクロールスピードより早くシフトさせることで、青がスクロールに応じて光っているように見えるようになっています。

これを見つけたとき僕はあまりの驚きと感動に20秒ほど開いた口が塞がらなかったです。恐るべしApple。

 <body>
    <div class="white_space"></div>

    <div class="whole">
      <div class="backlights">
        <img src="image/gradient_cercle.png" class="light1" alt="" />

        <img src="image/gradient_cercle.png" class="light2" alt="" />

        <img src="image/gradient_cercle.png" class="light3" alt="" />
      </div>

      <div class="grid">
        <div class="box1"></div>
        <div class="box2">
          <h2 class="box_text1">Appleの<br />製品ページは</h2>
        </div>
        <div class="box3"></div>
        <div class="box4">
          <h2 class="box_text2">素敵</h2>
        </div>
        <div class="box5"></div>
        <div class="box6">
          <h2 class="box_text3">アイディアが<br />すごい</h2>
        </div>
        <div class="box7"></div>
        <div class="box8">
          <h2 class="box_text3">
            実現できる<br />範囲でデザインを<br />考えるって
          </h2>
        </div>
        <div class="box9">
          <h2 class="box_text4">思ってるよりすごい</h2>
        </div>
        <div class="box10"></div>
      </div>
    </div>

    <div class="white_space"></div>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js"
      integrity="sha512-NBLGIjYyAoYAr23l+dmAcUv7TvFj0XrqZoFa4i1o+F2VvF9SrERyMD8BHNnJn1SEGjl1AouBDcCv/q52L3ozBQ=="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rellax/1.9.1/rellax.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/scrollreveal.js/3.0.3/scrollreveal.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
    <script src="javascript/index.js"></script>
  </body>

.white_space {
  width: 100%;
  display: block;
  height: 100vh;
  background-color: #000000;
}

.whole {
  width: 700px;
  height: 100vh;
  display: block;
  margin: auto;
  position: relative;
  overflow: hidden;

  .backlights {
    width: 100%;
    height: 100vh;
    position: absolute;
    top: 0;

    img {
      width: 300px;
      height: auto;
      display: block;
      transform-origin: center;
    }

    .light1 {
      position: absolute;
      top: -100px;
      right: 50px;
      opacity: 0;
    }

    .light2 {
      position: absolute;
      top: 180px;
      left: 0;
      right: 0;
      display: block;
      margin: auto;
      opacity: 0;
    }

    .light3 {
      position: absolute;
      top: 400px;
      left: 50px;
      opacity: 0;
    }
  }

  .grid {
    position: absolute;
    top: 0;
    display: grid;
    grid-template:
      "head_left head_left head_right"
      "second_left second_center second_right"
      "third_left third_center third_right"
      "bottom_left bottom_right bottom_right";
    width: 100%;
    min-height: 100vh;
    gap: 15px;

    h2 {
      color: #fff;
      font-family: "Noto Sans JP";
      line-height: 2;
    }

    .box1 {
      grid-area: head_left;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
    }

    .box2 {
      grid-area: head_right;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
      display: flex;
      justify-content: center;
      align-items: center;

      h2 {
        font-size: 22px;
      }
    }

    .box3 {
      grid-area: second_left;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
    }

    .box4 {
      grid-area: second_center;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
      display: flex;
      justify-content: center;
      align-items: center;

      h2 {
        font-size: 50px;
      }
    }
    .box5 {
      grid-area: second_right;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
    }
    .box6 {
      grid-area: third_left;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
      display: flex;
      justify-content: center;
      align-items: center;

      h2 {
        font-size: 23px;
      }
    }
    .box7 {
      grid-area: third_center;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
    }
    .box8 {
      grid-area: third_right;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
      display: flex;
      justify-content: center;
      align-items: center;

      h2 {
        font-size: 23px;
      }
    }
    .box9 {
      grid-area: bottom_left;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
      display: flex;
      justify-content: center;
      align-items: center;

      h2 {
        font-size: 22px;
      }
    }

    .box10 {
      grid-area: bottom_right;
      background-color: #000000;
      box-shadow: 0 0 3px gray;
    }
  }
}

「ポートレートモードに、
夜の表情を。」

今回のiPhone12では画像が後ろから現れて後からテキストが続くようなちょっとお洒落だけど似たようなレイアウトをよく見るこのシーンが多く使われていましたね!

 <body>
    <div class="white_space"></div>

    <div class="photo">
      <div class="text_cover">
        <h1>誰よりも、美しく。</h1>
      </div>

      <div class="whole">
        <img src="image/girl.jpg" class="mainimg" alt="" />
        <p class="detail">
          ナイトモードのポートレートを広角カメラで。明かりに照らされた建物や街灯など、背景のあらゆる光を際立たせながら、あざやかな色と美しいボケのある写真が撮れます。
        </p>
      </div>
    </div>
    <div class="white_space"></div>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js"
      integrity="sha512-NBLGIjYyAoYAr23l+dmAcUv7TvFj0XrqZoFa4i1o+F2VvF9SrERyMD8BHNnJn1SEGjl1AouBDcCv/q52L3ozBQ=="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rellax/1.9.1/rellax.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/scrollreveal.js/3.0.3/scrollreveal.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
    <script src="javascript/index.js"></script>
  </body>
.white_space {
  width: 100%;
  display: block;
  height: 100vh;
  background-color: #000000;
}

.photo {
  display: block;
  width: 800px;
  margin: auto;

  .text_cover {
    width: 100%;
    height: 700px;
    display: block;
    margin: auto;
    position: relative;
    z-index: 2;
    background: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));

    h1 {
      margin: 0 0 0 10px;
      color: #fff;
      font-size: 40px;
      font-family: "Noto Sans JP";
    }
  }

  .whole {
    transform-origin: top;
    margin: -600px auto 20px auto;

    .mainimg {
      width: 100%;
      display: block;
      margin: 0 auto 20px auto;
    }

    .detail {
      width: 700px;
      display: block;
      margin: auto;
      font-size: 15px;
      color: #fff;
      line-height: 1.2;
      font-family: "Noto Sans JP";
    }
  }
}

var photo = gsap
  .timeline()
  .from(".whole", {
    scale: 0.8,
    opacity: 0.3,
  })
  .from(".detail", {
    opacity: 0,
    ease: Circ.easeOut,
  });

var scene_photo = new ScrollMagic.Scene({
  triggerElement: ".whole",
  triggerHook: 0.2,
  duration: 600,
})
  .setTween(photo)
  .setPin(".whole")
  .addTo(controller);

「使いたいものが
すぐに使える。」

ScrollMagicとGSAPの集大成って感じですね。

でも1つ1つを見つめればこれまでのコーディングと大きく異なる箇所はありません。

僕の場合はiPhoneの上に乗っているアプリの動きをiPhone基準で作ってから、それと同時に全体の3つのiPhoneを縮小させるアニメーションを発火させています。

  <body>
    <div class="white_space"></div>

    <div class="apple_ios">
      <div class="phone1">
        <img src="svg/phone_object1.svg" alt="" />
      </div>
      <div class="phone2">
        <img src="svg/phone_object2.svg" class="img1" alt="" />
        <img src="svg/icon1.svg" class="img2" alt="" />
        <img src="svg/icon2.svg" class="img3" alt="" />
        <img src="svg/icon3.svg" class="img4" alt="" />
        <img src="svg/icon4.svg" class="img5" alt="" />
        <img src="svg/icon5.svg" class="img6" alt="" />
        <img src="svg/icon6.svg" class="img7" alt="" />
        <img src="svg/icon7.svg" class="img8" alt="" />
        <img src="svg/icon8.svg" class="img9" alt="" />
      </div>
      <div class="phone3">
        <img src="svg/phone_object3.svg" alt="" />
      </div>
    </div>
    <div class="white_space"></div>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.4.5/vivus.min.js"
      integrity="sha512-NBLGIjYyAoYAr23l+dmAcUv7TvFj0XrqZoFa4i1o+F2VvF9SrERyMD8BHNnJn1SEGjl1AouBDcCv/q52L3ozBQ=="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rellax/1.9.1/rellax.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/scrollreveal.js/3.0.3/scrollreveal.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
    <script src="javascript/index.js"></script>
  </body>
.white_space {
  width: 100%;
  display: block;
  height: 100vh;
  background-color: #000000;
}

.apple_ios {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  width: 1000px;
  margin: auto;
  background-color: #000000;
  transform-origin: top;

  .phone1,
  .phone3 {
    width: 300px;

    img {
      width: 100%;
      height: auto;
    }
  }

  .phone2 {
    width: 300px;
    position: relative;

    .img1 {
      width: 100%;
      z-index: -1;
    }

    .img2,
    .img3,
    .img6,
    .img7,
    .img8 {
      width: 60px;
    }

    .img4,
    .img5,
    .img9 {
      width: 120px;
    }

    .img2 {
      position: absolute;
      top: 60px;
      left: 20px;
    }

    .img3 {
      position: absolute;
      top: 60px;
      left: 90px;
    }

    .img4 {
      position: absolute;
      top: 60px;
      right: 20px;
    }

    .img5 {
      position: absolute;
      top: 250px;
      left: 20px;
    }

    .img6 {
      position: absolute;
      top: 250px;
      right: 90px;
    }

    .img7 {
      position: absolute;
      top: 310px;
      right: 20px;
    }

    .img8 {
      position: absolute;
      bottom: 60px;
      left: 20px;
    }

    .img9 {
      position: absolute;
      bottom: 60px;
      right: 20px;
    }
  }
}
var whole_ios = gsap.from(".apple_ios", {
  scale: 2.5,
});

var scene_whole_ios = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(whole_ios)
  .setPin(".apple_ios")
  .addTo(controller);

var with1 = gsap.from(".img1", {
  opacity: 0.1,
});

var scene_with1 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with1)
  .addTo(controller);

var with2 = gsap.from(".img2", {
  x: -200,
  y: -30,
  scale: 1.5,
});

var scene_with2 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with2)
  .addTo(controller);

var with3 = gsap.from(".img3", {
  x: -80,
  y: 80,
  scale: 1.5,
});

var scene_with3 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with3)
  .addTo(controller);

var with4 = gsap.from(".img4", {
  x: 320,
  y: -30,
  scale: 1.5,
});

var scene_with4 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with4)
  .addTo(controller);

var with5 = gsap.from(".img5", {
  x: -400,
  scale: 1.5,
});

var scene_with5 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with5)
  .addTo(controller);

var with6 = gsap.from(".img6", {
  x: 200,
  y: -200,
  scale: 1.5,
});

var scene_with6 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with6)
  .addTo(controller);

var with7 = gsap.from(".img7", {
  x: 320,
  y: 120,
  scale: 1.5,
});

var scene_with7 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with7)
  .addTo(controller);

var with8 = gsap.from(".img8", {
  x: -200,
  y: 200,
  scale: 1.5,
});

var scene_with8 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with8)
  .addTo(controller);

var with9 = gsap.from(".img9", {
  x: 320,
  y: 320,
  scale: 1.5,
});

var scene_with9 = new ScrollMagic.Scene({
  triggerElement: ".apple_ios",
  triggerHook: 0.2,
  duration: 1000,
})
  .setTween(with9)
  .addTo(controller);

どうでしたか??

個人的にはやっぱりAppleの「神は細部に宿る」って感じの凄さをコーディングしながら感じました。

やっぱりプログラミング勉強中の人間が挑戦しようとしても見た目がどうしてもまとまらなかったりダサくなったり、安っぽく見えてしまいます。

Webデザインにおいて共通することだとは思いますが、大事なのは「デザイン」で、「コーディング」に関してはさしてレベルの高い技術が求められるわけではないということを実感しました。

#apple偉大