ちら帳

喉元を過ぎると熱さを忘れる自分の為の、ちら裏メモ帳ブログです。

React VR : 仮想キーボードを使った入力

React VRで仮想キーボードを扱えるパッケージを見つけたので、使ってみました。

www.npmjs.com

外観はこんな感じになります。キー入力はカーソルを合わせてクリックする方式です。

f:id:chira_pym:20170621205247p:plain

使い方

インストー

React VRのプロジェクト下に移動して仮想キーボードのパッケージをインストールします。

npm install react-vr-textinput

react-vr-textinput/static_assets 内にあるup.pngとdown.pngをプロジェクト内のstatic_assetsにコピーしておきます。

カーソルの設定

キーボードを使うにはカーソルが必要になります。 注視カーソルで入力するのはつらいので、コントローラーかマウスを使うことにします。

コントローラー

コントローラーは公式のサンプルにあるThreeDOFRayCasterを利用すると簡単に実装できます。

github.com

コントローラーの表示はこんな感じになります。

f:id:chira_pym:20170701191344p:plain

マウス

マウス用のraycasterはもともと用意されているものを拡張したクラスを用意します。

import {
    MouseRayCaster
} from 'ovrui';

export default class MyMouseRayCaster extends MouseRayCaster {

    drawsCursor() {
        return true;
    }
}
client.js

raycastersオプションに各raycasterを指定します。加えてコントローラーの描画にsceneの指定も必要になります。

// Auto-generated content.
// This file contains the boilerplate to set up your React app.
// If you want to modify your application, start in "index.vr.js"

// Auto-generated content.
import {VRInstance} from 'react-vr-web';
import ThreeDOFRayCaster from '../src/ThreeDOFRayCaster';
import MyMouseRayCcaster from '../src/myMouseRayCaster';
import * as THREE from 'three'

function init(bundle, parent, options) {
  const scene = new THREE.Scene();
  const vr = new VRInstance(bundle, 'TestInput', parent, {
    // Add custom options here
    raycasters: [
        new ThreeDOFRayCaster(scene),
        new MyMouseRayCcaster()
     ],
     scene: scene,
     cursorVisibility: 'auto',
    ...options,
  });
  vr.render = function() {
    // Any custom behavior you want to perform on each frame goes here
  };
  // Begin the animation loop
  vr.start();
  return vr;
}

window.ReactVR = {init};

入力フィールドの表示

サンプルコードをもとに仮想キーボードの入力フィールドを表示します。 Submitを押すとフィールドの隣に入力した文字列が表示されるようになっています。

import React from 'react';
import {
  AppRegistry,
  asset,
  Pano,
  Text,
  View
} from 'react-vr';
import TextInput from 'react-vr-textinput'

export default class TestInput extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      text : ''
    };

    this.submitHandler = this.submitHandler.bind(this);
  }  
  
  submitHandler(string) {
    this.setState({text : string});
    console.log('the text received by the submitHandler is ' + string);
  }
   
  render() {
    return (
      <View>
        <Pano source={asset('chess-world.jpg')}/>
        <TextInput onClick={this.clicked} onSubmit={this.submitHandler} rows={1} 
        cols={20} x={-1} y={0.2} z={-1.5} rotateY={null} rotateX={null} textColor={'black'} backgroundColor={'pink'} keyboardColor={null} keyboardOnHover={null}/>
        <Text style={{transform: [{ translate: [0.2, 0.63 , -1.5]}]}}>{this.state.text}</Text>
      </View>

    );
  }
}

AppRegistry.registerComponent('TestInput', () => TestInput);

動作確認

コントローラー

f:id:chira_pym:20170701223222g:plain

マウス

2回目の入力でテキストの位置がおかしくなっていますが、マウス入力だからというわけではなく、 コントローラーで入力しても同じことが起きます。

f:id:chira_pym:20170701223048g:plain

遭遇した不具合

  • 入力フィールドが表示されず、TextInputがないとエラーが出た
      node_modules/react-vr-textinput/index.jsの内容に不備がありました。
//module.exports = require('./src/TextInput'); 
module.exports = require('./src/textInput');

追記:Issueを書いたら迅速に直してもらえました。ありがたや。

  • VRモードにすると入力フィールドが上の方に表示される
      HMDを被った瞬間、上の方に行ってしまうのはなぜなのでしょう。

  • VRモードにするとキーボードにカーソルが合わなくなる
      コントローラーから注視カーソルに変えたら直ったので、コントローラー側の実装とかみ合っていなかったようです。

  • VRモードでカーソルの動きにhoverのアニメーションがついてこれていない
      しばらく待っていると、あとからカーソルを合わせた順にキーが点滅していくので、表示の処理が追いついていないっぽいです。

  • VRモードでたまに入力内容がフィールドに反映されない
      おかしいなと思ってHMDを外して画面を見てみると、ちゃんと入力されているので、表示が間に合っていないようです。

GitHubの方に今後は処理速度の向上を目指していくみたいな記述があったので、アップデートに期待ですね。

This module is fully functional. Our next goal is to refactor for speed and also further enhance customizability through providing users even more props. We are also working on adding auto-complete support for faster typing. This will be an optional component that users can select to enable with their text input box and virtual keyboard. Please feel free to ask for additional functionality and we will try to add features as soon as possible.

今日のひとこと

ZenFone ARが発売されたせいか、最近 DayDreamやTangoについてのツイートを見かける機会が多くなりました。

楽しそうでうらやましいです。

Qiitaのぐるぐるまわるコメントテスト会場が面白い

とにかくはっちゃけてて面白いので未読の方はぜひ一読を。

qiita.com

ぐるぐるぐるー





<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<span class="fa fa-spin" style="color:#ff7f7f"><span class="fa fa-spin" style="color:#ff7fbf"><span class="fa fa-spin" style="color:="#ff7fff""><span class="fa fa-spin" style="color:#bf7fff"><span class="fa fa-spin" style="color:#7f7fff"><span class="fa fa-spin" style="color:#7fbfff"><span class="fa fa-spin" style="color:#7fffff"><span class="fa fa-spin" style="#7fffbf"><span class="fa fa-spin" style="color:#7fff7f"><span class="fa fa-spin"style="color:#bfff7f"><span class="fa fa-spin" style="color:#ffff7f"><span class="fa fa-spin" style="color:#ffbf7f"></span></span></span></span></span></span></span></span></span></span></span></span>

2017/6/16 追記

元の記事が盛り上がりすぎて重たくなっていますね。自分のスマートフォンからはもう見れなくなってしまいました。
もしかすると元の記事を見れずにこちらの記事を見ていただいてる方もいらっしゃるかもしれないので、とりあえず概要的なものを追記しておきます。

Font Awesomeという、とても有名なWebアイコンフォントがありまして、アイコンに対して表示効果(アニメーションとか)を付与するクラスなんかも提供されてたりします。

fontawesome.io

それで今回、Font Awesomeの効果をアイコン以外に使う遊びが流行っているのです。

発端となった記事

qiita.com

入力にHTMLタグを許容するタイプの入力フォームは対応大変そうですね。

技術的には

 .markdown-form * { animation: none !important; } 

とか指定しておけばアニメーションを止められると思うのですが、要件的にそれやっていいのかどうかとか色々とあると思うので。

おわり

2017/6/20 追記

QiitaでHTML要素の属性指定ができなくなったそうです(一部の外部サービスの貼り付けを除く)

http://blog.qiita.com/post/162037299989/disable-html-class
blog.qiita.com

過去にはbootstrapの属性を利用したXSS脆弱性もあったようですし、こういうのって色々としょうがないのかなと思う今日この頃です。

ただWebフォントを使えなくなるのはちょっと残念だなと思いました。
emojiじゃなくてシンプルなアイコンフォントを好んで使っていた方もいたのではないかと思うので。 これを機にemojiが拡張されたりとか…厳しいかなあ。

React VR : 注視カーソルでクリックする

React&Three.js初心者のため、週一で記事を書くのがそろそろ厳しくなってきました。ちらです。

今回はVR界隈ではちょくちょく見かける、見つめているとクリックできるボタンを作りました。

作ったボタン

ボタンを見つめている間、何も起きないと面白くないので、次のような効果もつけました。

  • ボタンを見つめているかどうかでボタンのテキストが変わる
  • ボタンを見つめている間はボタンがぶるぶるする
  • 物理クリック or 注視クリックされたらボタンのテキストが変わってクリック音もする

結果、できたものがこちらです(GIFを撮る都合上、VRモードにはしていません) f:id:chira_pym:20170612222738g:plain

こうして見てみると、もっとまともな例を作るべきだった気がしてなりませんが、寝ている顔文字をぶるぶるさせるのも、クリック時にお布団から飛び出るようにするのも実装しているときは結構楽しかったです。

実装

カーソルの表示

注視入力を実装するにあたりカーソルを表示させる必要があります。

詳しい説明については、以前記事に書いたので割愛します。 chira-memo.hatenablog.com

注視クリックできるボタンの実装

注視でボタンをクリックできるようなAPIはないので、onEnterの発火時にsetTimeoutを使って、クリックしたときに実行したい処理を1秒後に実行するようにします。
視線がボタンから外れたり、入力機器を使ってボタンがクリックされたときにはclearTimeoutでタイマーを解除します。

今は自力で実装する必要がありますが、UI的にはよくあるパターンのひとつなので、そのうち標準APIになったりするのかもしれません。

サウンドの再生についてはこちらを参考にしました。

facebook.github.io

アニメーションは…ドキュメントを読んでもあまりよく分からなかったので、参考になりそうなコードを見つけてきて見様見真似で書きました。変な書き方になってたらごめんなさい。

そのうちアニメーションについても記事が書けるといいなと思います。

"use strict";

import React from "react";
import {
    AppRegistry,
    asset,
    Pano,
    Text,
    Image,
    View,
    VrButton,
    Animated,
    VrSoundEffects
} from "react-vr";

import CylindricalPanel from "CylindricalPanel";

const Easing = require("Easing");

class ReactVrSample extends React.Component {
    render() {
        return (
            <View>
                <Pano source={asset("chess-world.jpg")} />
                <CylindricalPanel
                    layer={{ width: 2000, height: 720 }}
                    style={{ position: "absolute" }}
                >
                    <View
                        style={{
                            opacity: 1,
                            width: 2000,
                            height: 720,
                            alignItems: "center",
                            justifyContent: "center",
                            marginTop: 100
                        }}
                    >
                        <SleepingButton />
                    </View>
                </CylindricalPanel>
            </View>
        );
    }
}

class SleepingButton extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            text: "(¦3[___]",
            shakeValue: new Animated.ValueXY({ x: 0, y: 0 })
        };

        this.clicked = this.clicked.bind(this);

        VrSoundEffects.load({
            wav: asset("click.wav"),
            ogg: asset("click.ogg"),
            mp3: asset("click.mp3")
        });
    }

    render() {
        return (
            <Animated.View
                style={{
                    transform: this.state.shakeValue.getTranslateTransform()
                }}
            >
                <VrButton
                    onEnter={() => this.enter()}
                    onExit={() => this.exit()}
                    onClick={() => this.click()}
                >
                    <Text
                        style={{
                            margin: 10,
                            width: 400,
                            fontSize: 70,
                            fontWeight: "300",
                            borderRadius: 20,
                            backgroundColor: "pink",
                            textAlign: "center"
                        }}
                    >
                        {this.state.text}
                    </Text>
                </VrButton>
            </Animated.View>
        );
    }

    enter() {
        this.timeout = window.setTimeout(this.clicked, 1000);
        this.setState({ text: "(:3[___]" });

        const shakeValue = 1;

        this.animation = Animated.parallel([
            this.shake(shakeValue, shakeValue)
        ]);

        this.animation.start();
    }

    exit() {
        this.timerReset();
        this.clearAnimation();
        this.setState({ text: "(¦3[___]" });
    }

    click() {
        this.timerReset();
        this.clicked();
    }

    clicked() {
        this.clearAnimation();
        this.setState({ text: "(:з )=[___]" });
        VrSoundEffects.play({
            wav: asset("click.wav"),
            ogg: asset("click.ogg"),
            mp3: asset("click.mp3")
        });
    }

    timerReset() {
        if (!this.timeout) {
            return;
        }

        window.clearTimeout(this.timeout);
        this.timeout = null;
    }

    clearAnimation() {
        if (!this.animation) {
            return;
        }

        this.animation.stop();
        this.animation = null;
    }

    shake(x, y) {
        return Animated.sequence([
            Animated.timing(this.state.shakeValue, {
                duration: 30,
                toValue: { x, y },
                easing: Easing.linear
            }),
            Animated.spring(this.state.shakeValue, {
                toValue: { x: 0, y: 0 },
                friction: 0.5,
                tension: 400
            })
        ]);
    }
}

AppRegistry.registerComponent("ReactVrSample", () => ReactVrSample);

ボタンじゃなくてカーソルの方をアニメーションしたい

できればカーソルをリング型にして、進捗状況が分かるようなプログレスリングにしたいところなのですが、 カーソルの描画部分はライブラリの方にハードコードされてしまっているので難しいのが現状です。

github.com

makeDefaultCursorメソッド内にこんな感じのコメントがついているのでそのうちカスタマイズできるようになるかもしれません。

// TODO: Customize color or change color on hit.
// TODO: Support image provided by us or by user.

自分はおとなしくアップデートを待ちたいと思います(´・ω・`)

今日のひとこと

JSXのインデントのつけ方が全然分からないのでJsPreitterをSublime Textに入れました。
プラグインなしでは生きていけない体になりつつあります。

React VRでVrButtonに効果音をつける

今日も今日とてひっそりとReact VRをいじっております。ちらです。

今回は画面内にボタンを置いて、フォーカスが当たる・クリックされるといったイベントが発生したら効果音を鳴らすようにしてみます。

f:id:chira_pym:20170605031426p:plain

ボタンを表示する

ボタンの表示にはVrButtonコンポーネントを使います。 HTMLの<button>にとてもよく似ていますが、VrButtonはイベントをキャプチャするためのラッパーであり、外観を持たないようです。

実際にはTextやImageをラップして使います。

詳しくは例によってこちら。 facebook.github.io

VrButtonの入力に使えるボタンやキー

VrButtonでクリックイベントを検知できる入力については公式ドキュメントに以下の4つが挙げられています。

  • XboxゲームパッドのAボタン
  • キーボードのスペースキー
  • マウスの左クリック
  • スクリーンタッチ

XboxゲームパッドのAボタンが挙げられていますが、他のゲームパッドでも入力を検知することができます。 ただし、必ずAボタンが対応しているというわけではなく、Gamepad APIのGamepad#Buttons配列のインデックスが0のボタンが入力ボタンとなります。

ちなみに私はWindows 環境にOculus Touchを繋いで開発しているのですが、入力ボタンはスティックキーの押し込むところになっていました。

UnityだとOculus TouchのAボタンはjoystick button 0 が割り当てられているのですが、Gamepad APIだとキーマップが違うのでしょうか。

音を鳴らす

onClickイベントを検知して音源再生のAPIを叩く…のでもいいのですが、それをやってくれる専用のpropがVrButtonには用意されています。

  • onClickSound :ボタンにフォーカスが当たっている状態でクリックした時(厳密にはボタンなどを押して離した瞬間)に音源を再生します。
  • onLongClickSound :ボタンにフォーカスが当たっている状態で長めにクリックした時(厳密にはボタンなどを押して離した瞬間)に音源を再生します。
  • onEnterSound :ボタンにフォーカスが当たった瞬間に音源を再生します。
  • onExitSound :ボタンからフォーカスが外れた瞬間に音源を再生します。

なお、ボタンを押して離したタイミングではなく、ボタン押下時に音を鳴らしたい場合は、onButtonPressイベントを検知して、音源を再生する処理を書く必要がありそうです。

具体的にはあらかじめ再生したい音源をVrSoundEffects.loadでロードしておき、VrButttonのonButtonPressイベントが検知されたタイミングで、VrSoundEffects.playを使って音源を再生するといった流れになると思います。

サンプルプログラム

それでは前置きが長くなりましたが、VrButtonのonClick, onLongClick, onEnterSound, onExitSoundを使って効果音を鳴らすプログラムがこちらになります。

import React from 'react';
import { AppRegistry, asset, Pano, Text, View, VrButton} from 'react-vr';

export default class ButtonSample extends React.Component {

    constructor() {
        super();

        this.state = {
            sound:  {
                        wav: asset('click.wav'),
                        ogg: asset('click.ogg'),
                        mp3: asset('click.mp3')
                    }
        };
    }

    render() {
        const sound = this.state.sound;
        return (

            <View>
                <Pano source={asset('chess-world.jpg')}/>

                <View style={{
                    flex: 1,
                    flexDirection: 'row',
                    width: 5,
                    alignItems: 'stretch',
                    transform: [{translate: [-2.5, 0, -5]}],
                }}>

                <SampleButton text="Click" onClickSound={sound}/>

                <SampleButton text="LongClick" onLongClickSound={sound}/>

                <SampleButton text="Enter" onEnterSound={sound}/>

                <SampleButton text="Exit" onExitSound={sound}/>

            </View>
        </View>
        );
    }
}

export class SampleButton extends React.Component {

    static propTypes = {
        color: React.PropTypes.string,
        text: React.PropTypes.string,
        onClickSound: React.PropTypes.object,
        onLongClickSound: React.PropTypes.object,
        onEnterSound: React.PropTypes.object,
        onExitSound: React.PropTypes.object
    };


    static defaultProps = {
        color: 'coral',
        text: '',
        onClickSound: null,
        onLongClickSound: null,
        onEnterSound: null,
        onExitSound: null
    };

    constructor(props){
        super(props);
    }

    render(){
        return(

            <VrButton
                onLongClick={()=>{}}
                onClickSound={this.props.onClickSound}
                onLongClickSound={this.props.onLongClickSound}
                onEnterSound={this.props.onEnterSound}
                onExitSound={this.props.onExitSound}
                style={{flex: 1}}>
                    <Text style={{fontSize: 0.2, textAlign: 'center', margin: 0.1, height: 0.3, backgroundColor: this.props.color}}>{this.props.text}</Text>
            </VrButton>
        );
    }
}

AppRegistry.registerComponent('ButtonSample', () => ButtonSample);

onLongClickSoundの再生にはonLongClickの指定が必要

仕様なのか、バグなのか、onLongClickSoundのみ、音源を再生するには対応するイベントの定義が必要です。
onLongClickで何もしないで音だけ鳴らしたいということはほとんどないかもしれませんが、そうしたい場合は上のコードのようにonLongClick={()=>{}}を指定する必要があります。

VrButtonの詳しい実装についてはこちらのソースをお読みください。 github.com

ひとこと

cluster.でReact VRとかA-Frameとかの勉強会ってやってないのでしょうか。
おうちでのんびり聴講したいです。

React VRで頭の動きに追従するカーソルを表示する

VR初心者のちらです。

今回はVRでよくある、頭の動きに追従するカーソルの表示方法についてのお話です。

まずReact VRのカーソルシステムについてのドキュメントはこちら。

facebook.github.io

カーソルの実装

カーソルはRayCasterを利用して実装します。

学生時代のおぼろげな記憶で説明をするのも良くないので、レイキャストについての詳細は割愛しますが、ちゃんと調べたい人はレイキャストとかレイキャスティングで検索をかけるといいと思います。

RayCasterで実装が必要なメソッドは以下の3つになります。

  • getType - raycasterを一意に特定できるような文字列を指定します。
  • getRayOrigin - カメラを基準にしたときの光線の原点を3次元座標で指定します。
  • getRayDirection - カメラの向きをもとに光線の方向を3次元ベクトルで指定します。

さらにオプションで2つのメソッドが用意されています。

  • frame - アプリケーションのフレーム毎に呼び出されるメソッドです。
  • drawCursor - 目に見えるカーソルを描画するかどうか決定するメソッドです。

カーソル用に各メソッドを実装するのであれば、  

  • getType : 任意の文字列
  • getRayOrigin : [0, 0, 0] カメラの原点
  • getRayDirection : [0, 0, -1] カメラの正面方向
  • frame : 実装しない
  • drawCursor : true

とするのがいいと思います。

カーソルの可視性の制御

カーソルの可視性はcursorVisibilityというオプションで制御できます。
このオプションはclient.jsやindex.htmlでの初期化の際に設定することができます。

設定できる値は以下の3つです。

  • hidden - カーソルを常に非表示にします。デフォルトではhiddenになっています。
  • visible - カーソルを常に表示します。
  • auto - 入力イベントハンドラを持つコンポーネント(など)に視線がぶつかっているときにカーソルを表示します。

autoを設定する場合も、デバッグ中はvisibleにしておくのがよさそうです。

実装

今回はアプリケーション全体でカーソルを可視化する体でclient.jsに可視化処理を実装しました。
初期化時のオプションのraycastersにカーソル用のRayCasterを実装し、同じくオプションのcursorVisibilityをvisibleにします。

// Auto-generated content.
// This file contains the boilerplate to set up your React app.
// If you want to modify your application, start in "index.vr.js"

// Auto-generated content.
import {VRInstance} from 'react-vr-web';

function init(bundle, parent, options) {

  const vr = new VRInstance(bundle, 'ReactVrSample', parent, {
     // Pass in the custom font as an initialization property
     raycasters: [
          {
            getType: () => "mycursor",
            getRayOrigin: () => [0, 0, 0],
            getRayDirection: () => [0, 0, -1],
            drawsCursor: () => true
          } 
     ],
     cursorVisibility: 'visible',
     ...options,
  });

  vr.render = function() {
  // Any custom behavior you want to perform on each frame goes here
  };
  // Begin the animation loop
  vr.start();
  return vr;
};

window.ReactVR = {init};

せっかくなのでカーソルの当たり判定も確認できるようにします。
index.vr.jsに画面上にピンクの文字列を表示して、文字列にカーソルが当たっているときには色を赤に変える処理を書きます。

import React from 'react';
import { AppRegistry, asset, Pano, Text, View } from 'react-vr';


export default class ReactVrSample extends React.Component {
 constructor() {
    super();

    this.state = {textColor: 'pink'};
  }

  render() {
    return (
        <View>
        <Pano source={asset('chess-world.jpg')}/>
      <Text
        style={{color: this.state.textColor, 
            fontSize: 0.3,
            fontWeight: '400',
            layoutOrigin: [0.5, 0.5],
            paddingLeft: 0.2,
            paddingRight: 0.2,
            textAlign: 'center',
            textAlignVertical: 'center',
            transform: [{translate: [0, 0, -3]}],
          }}
        onEnter={() => this.setState({textColor: 'red'})}
        onExit={() => this.setState({textColor: 'pink'})}>
        This text will turn red when you look at it.
      </Text>
      </View>
    );
  }  
};

AppRegistry.registerComponent('ReactVrSample', () => ReactVrSample);

確認

白い丸がカーソルです。GIFはありませんが、VRモードにして頭を動かすとちゃんと追従します。

f:id:chira_pym:20170528234908p:plain

文字の方を見ると、カーソルが文字に当たって文字の色が変わります。 f:id:chira_pym:20170528234940p:plain

ひとこと

A-Frameのtracked controllersのサンプルみたいにコントローラーの位置をトラッキングして手を表示したいのですが、公式サンプルはまだですか。

ReactVRで日本語フォントを扱う

ご無沙汰しております。ちらです。

以前からやるやる詐欺をしていたReact VRにとうとう手を出し始めました。
とは言っても、まだまだ、サンプルコード動いたー!やったー!って喜んでる段階ですが。

f:id:chira_pym:20170527131852p:plain

で、本題です。試しにサンプルコードのhello部分をはろーわーるどにしてみたのですが、こんな感じに文字化けしてしまいました。

f:id:chira_pym:20170527132352p:plain

日本語フォントをインストールしたら直ったので、備忘録として手順を残しておきます。

手順はこのドキュメントを参考にしました。
react-vr/Fonts.md at master · facebook/react-vr · GitHub

日本語フォントのダウンロード

ドキュメントを見ると、ovruiパッケージ内のfontsディレクトリに日本語フォント用のファイルが含まれているので、これを使えばいいよ的なことが書いてある気がします。

そこでまずプロジェクト直下のstatic_assetsにfontsディレクトリを作って、そこに必要なファイルをダウンロードしてきます。

必要なファイル: https://github.com/facebook/react-vr/raw/master/OVRUI/fonts/japanese.png https://github.com/facebook/react-vr/raw/master/OVRUI/fonts/japanese.fnt

client.jsを書き換える

次にドキュメントの真似をしながらvrディレクトリ内のclient.jsを書き換えます。こんな感じであってるかな?

// Auto-generated content.
// This file contains the boilerplate to set up your React app.
// If you want to modify your application, start in "index.vr.js"

// Auto-generated content.
import {VRInstance} from 'react-vr-web';
import * as OVRUI from 'ovrui';

var fallbackFonts = {
  '../static_assets/fonts/japanese.fnt': '../static_assets/fonts/japanese.png'
};

// use the embedded defaultFont and and fallbacks
var font = OVRUI.loadFont();
var count = 0;

function init(bundle, parent, options) {
  function addFallback(fallbackFont) {
    OVRUI.addFontFallback(font, fallbackFont);
    count--;
    if (count === 0) {
      // all fallbacks are loaded start the VRInstance
      // 'font' contains everything React VR needs to render <Text> elements with
      // your custom font.

      // Pass it to the boilerplate init code
      const vr = new VRInstance(bundle, 'ReactVrSample', parent, {
        // Pass in the custom font as an initialization property
        font: font,
        ...options,
      });

      vr.render = function() {
      // Any custom behavior you want to perform on each frame goes here
      };
      // Begin the animation loop
      vr.start();
      return vr;
    }
  }
  
  for (var key in fallbackFonts) {
    // allow each font to asynchronously load in parallel and start VR instance when all complete
    count++;
    OVRUI.loadFont(key, fallbackFonts[key]).then((fallbackFont) => {
      addFallback(fallbackFont);
    });
  }
}

window.ReactVR = {init};

確認

画面をリロードするとこんな感じで日本語が表示されます。やったーヾ( ・ω・)ノ

f:id:chira_pym:20170527131919p:plain

おわりに

React VRが1.1.0からバージョンが上がった際には、コードをコピペしても動かなくなる可能性があるので、その際は公式ドキュメントをご覧ください。
以上です。

esaの運用ルールについて少しだけ考えてみた( ⁰⊖⁰)

esaを使い始めた #トノコト

Boostnoteをうまく使いこなせない系エンジニアのちらです。

最近一人でesa.ioを使い始めました。

全体的にUIが使いやすく、見た目もかわいいので結構気に入っています。

あとWIPという概念がとても良いですね。

ブログとかチケットとかの文章はなんとなく綺麗に書かないといけないという強迫観念に縛られて生きているので、 アウトプットが遅くなりがちなのですが、そのあたりの心理的障壁が下がって、個人的にはすごく刺さるものがありました。

また、Chrome拡張のtsuibamiを利用すると、メモ速度が爆速になります=͟͟͞͞ (\( ⁰⊖⁰)/)
ChromeVivaldiを使っている方におすすめです。

社内のナレッジ共有にも使いたい #トノコト

社内のナレッジ共有が滞りがちなので、会社でもesaを使えたらいいなあと思っています。
でも組織で使う場合は、運用ルールが整備されていないと、せっかくのツールの良さも活かされなかったりするんですよね…

ということで、esa歴3日の素人ながら、社内でのesaの運用ルールやテンプレートについて少し考えてみました。

前提

今回運用を考える上での前提やら想定やらです。

  • 社内全体で使用する(規模は中小レベルを想定)
  • 個人の知識の共有をメインとするが、他にも社内で共有したいことがあれば、基本的に自由に投稿して良い
  • 社外秘・社内秘の情報だけは書かない
    • プロジェクト内のルールや特有の設定などに関しては、プロジェクト管理ツール(Redmineなど)に書く
    • その他、外に出せない情報は社内専用の情報共有場所(社内wikiなど)に書く
  • WebhookはEmailのみ使用

WebhookにEmailしか使わないのは、単に私が職場でチャットサービスを使ってなくて、SlackやHipChatに詳しくないからです。

カテゴリ

何をカテゴリにして、何をタグにするかを悩みましたが、とりあえずこんな感じになりました。

※PCから見たときに縦に長くなるので、技術情報の第三階層はリストにするのをやめました。

カテゴリの説明

esa Tips:
esaのTips集です。 公式のProTipカテゴリみたいなものです。

経営:
エンジニアも経営のことを知っていた方が良いとよく話を聞くので、経営カテゴリを用意しました。

不勉強なのでこれ以上階層を切れませんでしたが、きっと経理、組織論、法務あたりの情報を共有するのだと思います。

マーケティング:
Webマーケティングの情報に関するカテゴリです。
営業の人が使う想定で用意しました。

このカテゴリも詳しくないので、これ以上の階層を切っていません。
Webエンジニア的にはSEOアクセス解析についての情報が共有されるとうれしいです。

技術情報:
技術に関する備忘録、はまったこと、発見したことなどを共有するカテゴリです。
一部、カテゴリを言語で切るか、フレームワークで切るか悩みましたが、なるべく言語で切ることにしました。

他のカテゴリとの関係を考えて、言語、フレームワークは必ずタグで記述する決まりにします。
この時、タグに言語やフレームワークのバージョン番号は書かない方針にします。

面倒がって書かない人がいるでしょうし、バージョンが関係する情報はその旨がドキュメント内に書かかれるはずなのでそれで良いかなという判断です。

QAコーナー:
QAコーナーはStack Overflow的なカテゴリです。
ここに記事が投稿されたらメーリスに通知するようにしておきます。

内容が解決したら、アーカイブするか、技術情報のカテゴリへ移します。

社内チャットなど、すでにナレッジコミュニティが他にあるなら、このカテゴリは無くてもいいと思います。

イベント:
技術展や勉強会といったイベントに関する情報を共有するカテゴリです。

イベントを主催するときのお知らせや参加レポを共有します。 開催情報のカテゴリに記事が投稿されたらメーリスに通知するようにしておきます。

書籍:
最近読んだ技術書やビジネス書などの情報を共有するカテゴリです。 本の概要や内容に関するメモ、所感を書いて共有します。

ドキュメントを書こうと思った本のドキュメントが既出の場合は、コメントにメモや感想を追記します。

これ以上、下の階層を増やすどうか悩みましたが、とりあえずタグを使った運用にして、ドキュメントが増えてきたらカテゴリを増やせばいいと思います。

ポエム:
ここでいうポエムとは以下のような文章を指します。

ビジネス文章としての整合性や第三者からの検証性を必ずしも重視せず,書き手自身の理想であったり熱意だったり危機感だったり,そういう何らかの感情の発露を自分の中で反芻してとりまとめた表現した文章や図面の事。規模は数行から数十行であることが多い。
第1回 事業会社における開発とポエム:会社で「ポエム」を綴ろう! ~ポエム駆動で理想を語ると社内の風が変わる!~|gihyo.jp … 技術評論社 

ポエム駆動型開発を取り入れないにしても、こういうのを吸い上げられる場所って大事だと思うんですよね、というポエム。

雑記:
これまで紹介したどのカテゴリにも属さないドキュメントを共有するカテゴリです。

どのカテゴリに置いてよいかわからないドキュメントは、ひとまずここに書いておいて、 あとで新しくカテゴリを増やすなり、既存のカテゴリに移すなりするといった運用もできます。

テンプレート

ドキュメントをさくっと書けるように、必要事項を埋めるだけで良いようなテンプレートを用意してみました。

インストール手順テンプレート

f:id:chira_pym:20170320014119p:plain

#:raised_hand: 前提

### :dvd: インストールするソフトウェアとバージョン  
piyo 1.0

###  :computer: OS  
Windows 10

### :cd: 事前にインストールが必要なソフトウェア
なし

# :memo: 手順
1. hoge
2. fuga

#:warning: 注意点

イベント案内テンプレート

f:id:chira_pym:20170320041825p:plain

# :information_source: 基本情報

:calendar:  日時 : 
 
:office:  会場 : 

:black_nib:  テーマ:

# :scroll: 概要

URL: http://google.com

イベント参加レポテンプレート

f:id:chira_pym:20170320040939p:plain

# :information_source:  基本情報

:calendar:  日時 :
 
:office:  会場 :

:black_nib:  テーマ:

# :scroll: 概要

# :thumbsup: 良かった発表・勉強になったことなど  

# :books: 資料
<!--
このようにSlide Shareのスクリプトを埋め込むことができます。
<script async class="speakerdeck-embed" data-id="5633a9b0599d01326f2b4e55f5ecb48c" data-ratio="1.41436464088398" src="//speakerdeck.com/assets/embed.js"></script>
-->
# :coffee:   所感

書籍テンプレート

f:id:chira_pym:20170320133311p:plain

# :blue_book: タイトル

# :scroll: 概要

# :memo: メモ
<!--
読んだことに関して、何かメモしておきたいことがあれば記入してください。
-->

# :coffee:   所感

# :clipboard:  アンケート(任意)

**評価** : :star: × n

## 良かったこと
なし

## 良くなかったこと
なし

## どんな人におすすめか
なし

最後は管理者が頑張るしかない #トノコト

なるべく人が悩む要素はつぶしましたが、それでも、この構成でAWSやDocker関連のドキュメントはどこにどう書こうか、自分でも悩むので、まだまだわかりにくいカテゴリルールになっていると思います。

また、タグの付け方のルールをしっかり定義していないので、そのあたりに起因する問題も起きそうです。

ということで、実際に運用したわけではありませんが、運用時には以下のことが想定されます。

  • カテゴリやタグが乱立する
  • ドキュメントに期待するタグをつけてもらえない
  • ドキュメントが重複する

もともと情報が育ったら整理することを前提としたサービスなので、週1、あるいは月1でドキュメントを整理する時間を設けて、その時にこういったドキュメントの整理もした方が良さそうです。

その時に、それこそドキュメントの整理時のルールを共有するようにしたら良いのではないかと思います。

所感

遅筆なのでここまで書くのに体力と時間をかなり持っていかれました。
お昼寝して起きたら、もっとすごい人たちのちゃんとした記事が上がってるに違いないです。

それではおやすみなさい(:3[___]