astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

Play Framework 2.6がやってきた(正確にはやってきてた

f:id:astamuse:20170815181256p:plain

お久しぶりです。開発部のYanagitaです。
宮崎は相変わらず蒸し暑い日が続いていて、ゲリラ豪雨に悩まされた頃が少し恋しくも感じてます。

私の回はこれまでPlay Frameworkについて記事をいくつか書きましたが、
ブログの担当が回ってくるまでの間にPlay Frameworkのバージョンが2.5系から2.6系へ上がったので、 今回は2.6にアップデートされたPlay Frameworkの更新内容についてチェックしたいと思います。
(Play Frameworkを開発する会社の社名もTypesafe社からLightbend社に変わってましたね)

Play Framework 2.6の更新内容

以下、Play FrameworkはPlayと記述します。

Scala 2.12のサポート

Play2.6もScala2.12に対応しました。
Scala2.12へのアップデートを検討している弊社開発チームとしてはとても大きなアップデートの一つです。 Play2.6はScala2.11にも対応しているため、build.sbtの記述を変更するとこでScalaのバージョンを変更できます。
Scala 2.12の場合(デフォルト)

scalaVersion := "2.12.2"

Scala 2.11の場合

scalaVersion := "2.11.11"

グローバルステートへのアクセス制限

Play2.6ではアプリケーションからplay.api.Play.current/play.Play.application()へのアクセスが非推奨となっています。
以下の設定を行うことで呼び出し時に例外をスローすることができます。

play.allowGlobalApplication=false

Akka HTTPの採用

これまでWebサーバとしてバックエンド部分にデフォルトでNettyが使用されていましたが、Play2.6からAkka HTTPに変更となります。
一応、これまで標準のNettyもサポートを続けていますのでNettyを使用する場合はbuild.sbtの記述を変更できます。

lazy val root = (project in file("."))
  .enablePlugins(PlayScala, PlayNettyServer)
  .disablePlugins(PlayAkkaHttpServer)

起動時に使用するサーバをNettyに変更することもできます。

sbt run -Dplay.server.provider=play.core.server.NettyServerProvider

HTTP/2サポート(実験的)

HTTP/2への対応が行われました。ただし、これはAkka Http側の仕様(API)が変更される可能性があるため実験的とされています。
また、テストも完全ではないため実使用はもうしばらく避けたほうが良さそうです。
HTTP/2の有効化

lazy val root = (project in file("."))
  .enablePlugins(PlayJava, PlayAkkaHttp2Support)

リクエスト属性の追加

リクエスト内にタグを情報として格納していましたが非推奨となり、Play2.6からは属性として格納することが薦められています。

// 属性名と格納するオブジェクトを宣言
object Attrs {
  val User: TypedKey[User] = TypedKey.apply[User]("user")
}

// リクエスト情報から属性値を取得
val user: User = req.attrs(Attrs.User)
// リクエスト情報に属性を追加
val newReq = req.addAttr(Attrs.User, newUser)

Route modifiersタグ

route単位にタグを指定することで動作の調整が可能となります。 例えば、CSRFフィルターをあるrouteにのみ非適用とする場合に「nocsrf」タグが用意されています。
このタグをrouteの直前に記述することでそのrouteにはCSRFフィルターが適用されません。

+ nocsrf
POST /api/foo/bar ApiController.foobar

独自のタグも生成するが可能です。複数タグを設置する場合は、半角空白区切りでタグを並べます。

フィルタの強化

Play2.6ではセキュリティに特化したフィルタがデフォルトでセットされるようになりました。

  • play.filters.csrf.CSRFFilter ← CSRFへの対策フィルタ
  • play.filters.headers.SecurityHeadersFilter ← XSSとクリックジャッキングの対策フィルタ
  • play.filters.hosts.AllowedHostsFilter ← DNSリバインディングの対策フィルタ

独自のフィルタを追加、または無効化する場合はapplication.confに記述します。
フィルタを追加する場合

play.filters.enabled+=MyFilter // 既存フィルタに追加するので「+=」を使用する

フィルタを無効化する場合

play.filters.disabled+=MyFilter

JWT Cookiesの対応

Play2.6では、JSONウェブトークンセッションとフラッシュクッキーをJWT形式に対応しました。
標準化された署名Cookieデータ、有効期限、署名でより柔軟性を実現しています。

テストの改善

Play2.6ではplay.api.testパッケージに新しいユーティリティクラスが追加されます。

  • Injecting 依存注入する際にapp.injector.instanceOfを使用していたが、Injecting traitを使用することで簡潔に書けるようになります。
    Play2.5まで
"test" in new WithApplication() {
  val executionContext = app.injector.instanceOf[ExecutionContext]
  ...
}

Play2.6から

"test" in new WithApplication() with Injecting {
  val executionContext = inject[ExecutionContext]
  ...
}


* StubControllerComponents
StubControllerComponentsFactoryを利用してControllerComponentsを作成することでコントローラーのテストが可能となります。

val controller = new MyController(stubControllerComponents())


* StubBodyParser
StubBodyParserFactoryを利用してBodyParserを作成することでレスポンスボディのテストが可能となります。

val stubParser = stubBodyParser(AnyContent("hello"))

ファイルアップロード機能の改善

Play2.5までは、TemporaryFileオブジェクトがGCのタイミングでfinalizeを使用してテンポラリに残るファイルを削除してましたが、一定の条件がではGCがタイムリーに行われない問題がありました。
Play2.6からは、その問題を解消するため削除処理をfinalizeからFinalizableReferenceQueueとPhantomReferencesを使用するように変更しました。
また、全てのTemporaryFileはTemporaryFileCreatorを使用するように変更されたため、必要に応じて実装が変更できるようになりました。

それから、Akkaのスケジューラを使用して一時ファイルを削除する機能としてTemporaryFileReaperが用意されました。
TemporaryFileReaperの設定はapplication.confに記述します

play.temporaryFile {
  reaper {
    enabled = true
    initialDelay = "5 minutes" // ← アプリケーション起動後に5分後にTemporaryFileReaperを起動する
    interval = "30 seconds" // ← TemporaryFileReaper起動後、30秒毎にファイルをチェックする
    olderThan = "30 minutes" // ← 30分経過したファイルは削除する
  }
}

最後に

いくつか掻い摘んでの説明となりました。 漏れた分についてはまたタイミングをみてやりたいと思います。 詳しく知りたい方はドキュメントが公開されているのでこちらをご確認下さい。
Play Frameworkはマイナーアップデートでも仕様が大きく変わる傾向があるので、今後も変わったところを重点的に紹介して行ければと思います。

弊社では引き続きエンジニア・デザイナーの募集を続けています。
気になる方は下からご応募をお願いします!

そうだAsta4dでWebアプリケーションを作ろう(第6回)

FormFlow

最終回は簡単なFormなら本当に簡単に作れちゃうFormFlowについて書いていきます。
複雑なFormも作れますが、複雑なFormは複雑な処理になってしまうので、ここでは触れないこととします。
興味がある方はユーザーガイドとかサンプルとか見てみてください。

実装

例としては名前とメールアドレスを入力してサーバーに送信するFormを例にして解説していきます。
stepはinput -> confirm -> completeという順番で行うものとします。

良くある簡易登録みたいな感じですかね。
流石にデータをDBに入れるとか登録完了メール送信とかはスコープ外です。

URLRule

まずはFormFlow用にURLRuleを作成します。
Ruleは簡単で、同じURLをGET、POSTで作れば良いです。
GETは最初のページ(input)用でPOSTはそれ以降のページ(confirm、complete)用です。

package com.astamuse.blog_sample.rules;

import static com.astamuse.asta4d.web.dispatch.HttpMethod.GET;
import static com.astamuse.asta4d.web.dispatch.HttpMethod.POST;

import com.astamuse.asta4d.web.dispatch.mapping.UrlMappingRuleInitializer;
import com.astamuse.asta4d.web.dispatch.mapping.ext.UrlMappingRuleHelper;
import com.astamuse.blog_sample.handler.TestFormHandler;

public class UrlRules implements UrlMappingRuleInitializer{
    public void initUrlMappingRules(UrlMappingRuleHelper rules) {
        rules.add(GET, "/form").handler(TestFormHandler.class);
        rules.add(POST, "/form").handler(TestFormHandler.class);
    }
}

HandlerとSnippet

基本的な実装はフレームワーク側で提供されているので、必要なものだけ追加実装すれば問題ありません。
それぞれ説明していきます。

Handler

HandlerはClassicalMultiStepFormFlowHandlerTrait<T>を実装します。
Tはクライアント側から来るデータのデータ型を指定します。
データ型については後ほど書きます。

実装については幾つかの必須の実装と任意の実装があります。
軽くメソッドの説明をしてから全部の実装を載せます。

それではまずはメソッドの説明から。

public Class<T> getFormCls();

実装しなければなりません。
T型のクラスを返却すれば大丈夫です。

public String getTemplateBasePath();

実装しなければなりません。
FormのHtmlTemplateのSuffixを文字列で返却します。
細かいルールはHTMLの説明の時に書きます。

public void updateForm(T form);

実装しなければなりません。
クライアント側からのデータが渡ってくるのでDBへの保存などなどデータ型に対する処理を全て行ってください。
ここはconfirmのページからPOSTされた時にのみ呼ばれます。

public boolean treatCompleteStepAsExit();

任意の実装です。
完了画面を最後に表示するかのフラグを返却するメソッドでデフォルトの実装はtrueで表示しないとなっています。
今回は表示するとしたいと思うのでfalseを返却するよう実装を変更します。
ちなみにtrueの場合はURLRuleのPOSTに処理完了後のredirect処理を入れてあげてください。
ルールで設定すれば大丈夫です。

public FormValidator getValueValidator();

任意の実装です。
FormFlowのvalidation処理はBeanValidationで行うようになっていますが、カスタムクラスを実装する場合はここに独自で実装したクラスを返却するようにしてください。
今回はカスタム方法についても紹介するので、作成するクラスを返却するよう実装を変更します。

public TestForm createInitForm()

任意の実装です。
初期のフォームに表示するデータを返却します。
編集のフォームの時は今持っているデータを初期値として描画するや、途中離脱したユーザーに対して書いたデータを描画するといった使い方が出来ます。
今回はそういうのは無しなので、何も値を設定していないクラスを返却するようにします。

そんな実装をするとこんな感じになります。 updateFormは特に今回することがないので実装を省いてます。

package com.astamuse.blog_sample.handler;

import com.astamuse.asta4d.web.form.flow.classical.ClassicalMultiStepFormFlowHandlerTrait;
import com.astamuse.asta4d.web.form.validation.FormValidator;
import com.astamuse.blog_sample.form.TestForm;
import com.astamuse.blog_sample.utils.FormJsrValidator;

public class TestFormHandler implements ClassicalMultiStepFormFlowHandlerTrait<TestForm> {
    public Class<TestForm> getFormCls() {
        return TestForm.class;
    }

    public String getTemplateBasePath() {
        return "/html/form-";
    }

    public void updateForm(TestForm form) {
    }

    public boolean treatCompleteStepAsExit() {
        return false;
    }

    public FormValidator getValueValidator() {
        return new FormJsrValidator();
    }

    public TestForm createInitForm() {
        return new TestForm();
    }
}

Snippet

ClassicalMultiStepFormFlowSnippetTraitを実装します。
ただ、基本的にはすべてinterface側での実装で問題ないため、自分で実装する箇所はありません。

package com.astamuse.blog_sample.snippet;

import com.astamuse.asta4d.web.form.flow.classical.ClassicalMultiStepFormFlowSnippetTrait;

public class TestFormSnippet implements ClassicalMultiStepFormFlowSnippetTrait {

}

データ型

クライアントから来るデータのデータ型クラスについての説明です。
今回のFormでは名前ととメールアドレスをサーバー側に送信するというようなFormなので、データ型としてnameとmailを変数として用意します。

そんな訳で実装しました。

package com.astamuse.blog_sample.form;

import org.hibernate.validator.constraints.NotBlank;

import com.astamuse.asta4d.web.form.annotation.Form;
import com.astamuse.asta4d.web.form.annotation.renderable.Input;

@Form
public class TestForm {
    private String name;
    private String mail;

    @Input(nameLabel="名前")
    @NotBlank
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Input(nameLabel="メールアドレス")
    @NotBlank
    public String getMail() {
        return mail;
    }
    public void setMail(String mail) {
        this.mail = mail;
    }
}

と、これだけでは説明が不足しているので説明します。

@Form

FormFlowのデータ型クラスにはこのアノテーションが必須です。

@Input(nameLabel="名前")

このアノテーションはHTMLとデータ型の紐づけに必要なアノテーションです。
Inputタグであれば@Input、Selectタグであれば@Selectのようにタグと合わせたアノテーションを付けることで紐づけを行います。
他にもFormで使いそうなアノテーションはそろってるので、用途に合わせて使ってください。

今回、nameLabelを付けているのは、validationのためです。
説明は後ほどしますので、ここでは割愛します。

@NotBlank

こっちのアノテーションはValidation用のアノテーションです。
必要なアノテーションを付けておけば勝手にValidationしてくれるようになっています。
もちろん、Handlerの実装を変更して他のValidationを行うことや拡張することも可能となっています。

Validation

Validationはasta4dで用意しているJsrValidatorクラスがデフォルトでは使用されるようになっていますが、メッセージの形式の変更とか色々行いたいことが多くデフォルトだと日本語の対応も微妙なので、カスタムクラスを作成するようにしてます。 メッセージの変更はcreateMessageクラスの実装を変更すれば良いです。
データ型で設定したnameLabelは引数のfieldLabelに入ってきます。

この実装は必須ではないので、問題なければ実装しなくても大丈夫です。

ちなみにこのValidation機能のためにpom.xmlにhibernate-validatorを追加してあげる必要があります。
細かい仕様などは長くなりそうなので割愛しますので、別途調べていただけますと幸いです。

package com.astamuse.blog_sample.utils;

import javax.validation.Validation;
import javax.validation.Validator;

import org.apache.commons.lang3.StringUtils;

import com.astamuse.asta4d.web.form.validation.JsrValidator;

public class FormJsrValidator extends JsrValidator {

    //@formatter:off
    private static Validator validator = Validation.byDefaultProvider()
                                                    .configure()
                                                    .messageInterpolator(
                                                        new Asta4DIntegratedResourceBundleInterpolator(
                                                            new Asta4DResourceBundleFactoryAdapter("FormFlowValidationMessages")
                                                        )
                                                     )
                                                    .buildValidatorFactory()
                                                    .getValidator();
    //@formatter:on

    public FormJsrValidator() {
        this(true);
    }

    public FormJsrValidator(boolean addFieldLablePrefixToMessage) {
        super(validator, addFieldLablePrefixToMessage);
    }

    @SuppressWarnings("rawtypes")
    @Override
    protected String createAnnotatedMessage(Class formCls, String fieldName, String fieldLabel, String annotatedMsg) {
        return annotatedMsg;
    }

    @SuppressWarnings("rawtypes")
    @Override
    protected String createMessage(Class formCls, String fieldName, String fieldLabel, String fieldTypeName, String cvMsg) {
        if (addFieldLablePrefixToMessage && StringUtils.isNotBlank(fieldLabel)) {
            String msgTemplate = "%s : %s";
            return String.format(msgTemplate, fieldLabel, cvMsg);
        } else {
            return cvMsg;
        }
    }
}

HTML

今回のHTMLとしてはFormFlowのデフォルトであるinput -> confirm -> completeのフローを表示するため3つ作成します。

htmlファイル名はHandlerのgetTemplateBasePath()で返却するパス+各step名とする必要があります。
今回のケースであればform-input.html form-confirm.html form-complete.htmlと命名したhtmlの作成を行います。

各ファイルの中身はinput、confirmとcompleteで違います。
completeは最終ページなのでただの完了ページとなるため、好きな感じで良いです。 inputとconfirmに関してはルールの元に作成する必要があります。

  • formタグのmethodはPOSTにします
    • actionは設定しなくて良いです(そういうルールですし)
  • form送信時にstepの情報を入れて送信する必要があります
    • 特に表示する必要はないのでinput hiddenで作成します
    • name=“step-current"のvalueに現在のstep(input or confirm)を設定します
    • name=“step-failed"のvalueにサーバーサイドで失敗した際に行くstepを設定します
      • 今回は元のstepに戻るとします
  • 入力タグのnameでデータ型と紐づくので、nameを設定してください
    • アノテーション、変数名とhtml側の整合が取れている必要があります
  • confirmもinputタグとしていますが、Snippetで自動で置き換わります。nameが同じであれば問題ありません
    • 使いまわさない場合は、idに<変数名>-displayを設定したタグの箇所に描画してくれます
    • 今回は使いまわす形でhtmlを書いています
  • validationエラーの場合は<変数名>-err-msgをidに設定した箇所に描画してくれるので、タグだけ用意しておいてください
    • エラー時の戻り先として"step-failed"に設定した場所に存在する必要があります
  • Snippetの設定は入力箇所を対象となるよう設定してください

とまぁ、こんな感じでルールがあります。
色々と書きましたが、実際のHTMLは簡単です。
上のルールと照らし合わせながら見れば分かるレベルかと思います。

</html/form-input.html>

<html>
<head><meta charset="utf-8" /></head>
<body>
<div>
  <form method="POST">
    <div>
      <afd:embed target="/html/formContent.html"></afd:embed>
      <input type="hidden" name="step-current" value="input">
      <input type="hidden" name="step-failed" value="input">
      <button type="submit" name="step-success" value="confirm">送信
      </button>
    </div>
  </form>
</div>
</body>
</html>

</html/form-confirm.html>

<html>
<head><meta charset="utf-8" /></head>
<body>
<div>
  <form method="POST">
    <div>
      <afd:embed target="/html/formContent.html"></afd:embed>
      <input type="hidden" name="step-current" value="confirm">
      <input type="hidden" name="step-failed" value="confirm">
      <button type="submit" name="step-success" value="complete">送信
      </button>
    </div>
  </form>
</div>
</body>
</html>

</html/form-complete.html>

<html><head><meta charset="utf-8" /></head><body>
    <div>
        完了
    </div>
</body></html>

</html/formContent.html>

<html>
<head><meta charset="utf-8" /></head>
<body>
  <afd:snippet render="TestFormSnippet">
  <ul>
    <li>
      <span>名前</span>
      <div>
        <p><strong id="name-err-msg"></strong></p>
        <input type="text" placeholder="名前" name="name">
      </div>
    </li>
    <li>
      <span>メールアドレス</span>
      <div>
        <p><strong id="mail-err-msg"></strong></p>
        <input type="text" placeholder="test@astamuse.com" name="mail">
      </div>
    </li>
  </ul>
  </afd:snippet>
</body>
</html>

パーツの使いまわしについては機能的な紹介のために使用しましたが、実際の使用場面では別々になるかと思います。
しかし、そこもasta4dの良さをそこなわず対応することが可能となっていますので、

最後に

これで基本的なところは全て解説できたかと思います。
結構使いやすいフレームワークだと思いますので、興味を持った方はぜひとも使って世の中に広めていただければと思います。  

【モバイルフレンドリー対応:実例紹介】デザイナーが最低限考慮するべき3つのポイント

f:id:astamuse:20170801184442p:plain

アスタミューゼデザイン部のMatsumotoです。
早いもので2017年も折り返し。
弊社では、半年に1回人事考課があり、ちょうど先日2017年上期プロジェクトの振り返りを行っていました。

今回のエントリーでは、その考課期間に行ったastamuse.comのモバイルフレンドリー対応の一部を紹介したいと思います。

プロジェクト概要

astamuse.com 「モバイルフレンドリー対応」プロジェクト

現在8月9日時点の対応範囲

  • 技術一覧
  • ヘッダー&フッター
  • 技術詳細ページ
  • キーワード詳細ページ

背景

年々増えてくるモバイルからのトラフィックと、Googleがスマホ対応が不適切なサイトの検索順位引下げ発表により、リリース当初(2012年)はPC環境で使われることを想定してデザインしたastamuse.comもその状況を無視できなくなり、アクセス数が多いコンテンツからモバイルフレンドリー対応を行うことになりました。

年々増えていくモバイルトラフィック (astamuse.com全体の割合)

2012年 15%
2013年 15%
2014年 22%
2015年 27%
2016年 32%

目標

  • Googleのモバイルフレンドリーテストのアラートすべてクリアして、モバイルフレンドリーの基準を満たす。
  • 社内でユーザビリティーテストを行い、UXの向上を確かめる評価をもらう。

効果

  • モバイルフレンドリー対応により、各数値(滞在時間、直帰率、離脱率)の改善。
  • 検索順位UPにより、モバイルからのトラフィック増加。

はじめに

デザインをスタートさせる前に、まずは、Google Search Consoleのモバイルフレンドリーテストで現状把握。
みごと、モバイルフレンドリーテストで失格。

f:id:astamuse:20170727145353p:plain

エラー項目
  • テキストが小さすぎて読めません
  • コンテンツの幅が画面の幅を超えています
  • クリック可能な要素同士が近すぎます

上記エラーをひとつひとつクリアにしていくために実践した、最低限考慮すべき3つのポイントを紹介していきます。

ポイント1:ベストなフォントサイズにする

まずは、エラー項目「テキストが小さすぎて読めません」の対処。モバイルフレンドリーにおけるベストなフォントサイズを調べることからスタートしました。

技術詳細ページ(公開公報本文)の文章は長い、長い。
同じようにコンテンツのテキストが長いサイトといえば、ニュースサイト。参考にさせていただきました。 結果、長文が読みやすいなと感じたサイトの多くは基本フォントサイズは16pxでした。

ちなみにGoogleが推奨するフォントサイズも16px。
一番小さいサイズの推奨は12pxです。

body {
  font-size: 16px;
}

.small {
  font-size: 12px; /* 75% of the baseline */
}

.large {
  font-size: 20px; /* 125% of the baseline */
}

引用/参考: 読みやすいフォント サイズを使用する  |  PageSpeed Insights  |  Google Developers

弊社も世の中の読みやすいとされるフォントサイズに習い、本文のフォントサイズは最適とされる16pxにしました。
行の高さ1.75、1行の文字数は21文字に。(こちらも、他サイトを参考にベストな値で調整)

f:id:astamuse:20170727152416p:plain

ポイント2:リンク範囲と間隔のベストバランスを見つける

次に、エラー項目「クリック可能な要素同士が近すぎます」の対処。
スマートフォンは画面が小さいため、設置したリンクとリンクの間隔が十分にないと、指でタップする際に、うまく押せないことが多々あります。

具体的には、ページ上に密接して配置されている「ブックマーク」と「PDF」のボタンの箇所が、エラーを引き起こしていたと思われます。 ということで、クリックしやすいように、下記2点を考慮してデザインしていきました。

  • リンク範囲は大きくとる
  • リンク同士を近づけすぎず、十分な間隔を確保して、押し間違えを防止する(水平方向と垂直方向で5ミリ(32CSS ピクセル)以内に他のタップターゲットを配置しない)

f:id:astamuse:20170727124529p:plain

参考: Size Tap Targets Appropriately  |  PageSpeed Insights  |  Google Developers

ポイント3:コンテンツの幅に要注意

次に、エラー項目「クリック可能な要素同士が近すぎます」の対処。
スマートフォンの画面からはみ出している場合、このようなエラーがでます。 左右にスクロールしなければならない状態は、モバイルフレンドリーではないと評価されてしまうので、要注意。

さて、問題の箇所はどこだったかというと、ドロップダウンメニューの箇所。 タップのしやすさとタップゲートの間隔を十分にとったモバイルフレンドリーなUIに変更しました。

f:id:astamuse:20170727122724p:plain

参考: Size Content to Viewport  |  PageSpeed Insights  |  Google Developers

結果

  • Googleモバイルフレンドリーテストのエラーすべてクリア。モバイルフレンドリーの基準満たす。
  • 直帰率改善(3.17%減)
  • 離脱率改善(1.63%減)

※技術ページ・モバイルトラフィックのみに絞って計測(リリース前後1ヶ月で比較)
※直帰率、離脱率の数値については、非公開とさせていただきます。

数値の結果は、なんとも微妙でわずか数パーセントの改善のみ。 引き続き定点観測していき、継続して改善していく必要がありそうです。

ただ、目標の一つであった、Googleモバイルフレンドリーの基準はひとまず満たすことができたので、最低限の課題はクリアできたと思っています。

f:id:astamuse:20170727154928p:plain

また、社内のレビューは好評でしたので、実際のユーザーさまの声もぜひ聞かせていただけると嬉しいです。

日頃アスタミューゼをお使いのユーザーの皆さまへ

スマートフォン向けに新しくなったastamuseの技術ページをご覧いただき、読みやすさ、使い心地などのご意見・ご感想などTwitter@astamuseLabにお寄せいただけると嬉しいです。

先月世の中で話題となった特許より、astamuse.com技術ページのリンクをご紹介させていただきます。 ぜひスマートフォンにてご覧ください。

バーチャルホームロボット「Gatebox」

21世紀の“2次元の嫁?”として注目のバーチャルホームロボット。

参考: 【特許取得のお知らせ】Gatebox、「キャラクターとの対話関連技術」に関する特許を取得|Gateboxのプレスリリース

特許のたまご

卵かけご飯に合う卵として7年かけて開発。

参考: 開発7年「卵かけご飯に合う卵」、東日本で先行発売 - ITmedia ビジネスオンライン

Copyright © astamuse company, ltd. all rights reserved.