Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Next Mobile WebApplication

uupaa
December 02, 2013

Next Mobile WebApplication

このスライドは
2013-11-30 に開催された HTML5 Conference 2013 で

地下鉄・サクサク・これからのWebゲームアプリが備えるべき8つの機能

としてお話したものです

uupaa

December 02, 2013
Tweet

Other Decks in Programming

Transcript

  1. Next Mobile WebApplication
    uupaa
    2013-­11-­30

    View Slide

  2. Me
    @uupaa - 2012 join
    R&D
    App

    View Slide

  3. 2013-11-30 HTML5 Conference 2013
    Web
    8

    View Slide

  4. WebApp ?
    WebApp
    WebApp, Browser Game,
    SinglePageApplication, ES6, Storage, Cache,
    Audio, Canvas, WebWorker

    View Slide

  5. NativeApp vs WebApp
    NativeApp
    WebApp ?
    3D

    View Slide

  6. WebApp

    View Slide

  7. Single Page Application (SPA)
    SPA ?
    1
    WebApp

    View Slide

  8. SPA
    (BGM)
    WebApp
    800ms -> 200ms

    View Slide

  9. SPA

    View Slide

  10. Audio/WebAudio
    Audio

    BGM
    BGM SE
    Android

    View Slide

  11. WebAudio
    WebAudio m4a(AAC)
    WebAudio
    SoundSprite

    View Slide

  12. WebAudio
    ( )
    (input)
    ( )
    ( )
    (JavaScript )

    View Slide

  13. +-------+ +-------+ +-------+ +-------+ +-------+
    | SE[0] | | SE[1] | | SE[n] | | BGM-A | | BGM-B | BufferSource <>
    +---+---+ +---+---+ +---+---+ +---+---+ +---+---+
    | | | | |
    | | | +----+---+ +---+----+
    | | | | FADE-A | | FADE-B | BGM CrossFade <>
    | | | +----+---+ +---+----+
    +---------+---------+ +----+----+
    | |
    +----+---+ +--+---+
    | EFFECT | | LOOP | Effect/Loop Volume <>
    +----+---+ +--+---+
    +-------------+------------+
    +---+---+
    | MUTE | Mute <>
    +---+---+
    +------+------+
    | Compressor | <>
    +------+------+
    +------+------+
    | Distination | AudioContext.Distination
    +-------------+

    View Slide

  14. var ctx = new global.AudioContext();
    var node = {
    compressor: null,
    fade: [null,null], // CrossFade volume
    master: null, // master volume
    effect: null, // effect volume
    loop: null, // loop volume
    mute: null // mute
    };
    node.compressor = ctx.createDynamicsCompressor();
    node.mute = ctx.createGainNode();
    node.master = ctx.createGainNode();
    node.effect = ctx.createGainNode();
    node.loop = ctx.createGainNode();
    node.fade[0] = ctx.createGainNode();
    node.fade[1] = ctx.createGainNode();
    node.fade[0].connect(node.loop);
    node.fade[1].connect(node.loop);
    node.effect.connect(node.master);
    node.loop.connect(node.master);
    node.master.connect(node.mute);
    node.mute.connect(node.compressor);
    node.compressor.connect(ctx.destination);

    View Slide

  15. ( MIDI)

    View Slide

  16. WebAudio
    Web
    SE BGM
    OFF
    ON/OFF
    Android DualCore, 1GB RAM
    iOS iOS 7, iPhone 4S (iOS 6 )
    Chrome for Android 31
    http://hello.uupaa.net/issues/2/
    HE-AAC

    View Slide

  17. ( )

    View Slide

  18. Canvas
    65 70% 200dpi (in Google Play)
    $179 (Moto G)
    326dpi

    View Slide

  19. Canvas
    CanvasRenderingContext2D#toDataURL
    96dpi (ImageData)
    High Definition
    toDataURLHD
    toBlobHD
    createImageDataHD
    getImageDataHD
    putImageDataHD

    View Slide

  20. 2013 ImageData
    Width x Height Canvas ImageData Device
    480 x 320 600 KB iPhone (2007)
    960 x 640 2.3 MB iPhone Retina (2010)
    2048 x 1536 12 MB iPad Retina (2012)
    ImageData Pixel x 4byte(RGBA)

    View Slide

  21. 2015 ImageData
    2015 4K
    Width x Height Canvas ImageData Device
    960 x 640 2.3 MB iPhone Retina (2010)
    2048 x 1536 12 MB iPad Retina (2012)
    2560 x 1440 14 MB 2K Android (maybe 2014)
    3840 x 2160 31.6 MB 4K Android (maybe 2015)

    View Slide

  22. ImageData
    ImageData
    MB 16ms …
    for

    View Slide

  23. ?
    WebWorker

    View Slide

  24. WebWorker Canvas ? ?
    Canvas
    canvas.transferControlToProxy
    canvasProxy.setContext
    context.commit

    View Slide

  25. CanvasProxy (1 )

    // index.js
    var canvas = document.querySelector("canvas");
    var canvasProxy = canvas.transferControlToProxy(); // CanvasProxy を取得
    var canvasWorker = new Worker("BackgroundCanvasRender.js");
    canvasWorker.postMessage(canvasProxy, [canvasProxy]); // Worker に渡す
    // BackgroundCanvasRender.js
    onmessage = function(event) {
    var context = new CanvasRenderingContext2D();
    var canvasProxy = event.data;
    canvasProxy.setContext(context); // bind
    setInterval(function() {
    context.clearRect(0, 0, context.width, context.height);
    context.fillText(new Date() + "", 0, 100);
    context.commit(); // render
    }, 1000);
    };

    View Slide

  26. ?
    100 150MB
    GC
    window.gc()
    Worker Canvas
    drawImage …

    View Slide

  27. High Definition
    CanvasProxy + WebWorker

    View Slide

  28. Command Pattern
    ( )

    View Slide

  29. Canvas API
    // before
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, 100, 100);
    // after
    var canvasCommands = [
    ["fillStyle", "#fff"],
    ["fillRect", 0, 0, 100, 100]
    ];
    for (var i = 0, iz = canvasCommands.length; i < iz; ++i) {
    switch (canvasCommands[i]) {
    case "fillStyle": ... break;
    case "fillRect": ... break;
    }
    });

    View Slide

  30. :
    Android ( )
    , ,

    View Slide

  31. ( )
    Android Browser, Chrome for Android
    ( )

    View Slide

  32. DrawCall ( )
    Canvas API
    DrawCall
    DrawCall
    // before
    function drawCall1() {
    ctx.fillRect(...);
    }
    function drawCall2() {
    ctx.fillRect(...);
    }
    drawCall1();
    heavyRoutine();
    drawCall2();
    Chrome Canvas profiler
    DrawCall CanvasAPI

    View Slide

  33. + SnapShot, Movie

    View Slide

  34. + Remote Play
    DOM, CSS, Audio, Canvas
    App

    View Slide

  35. + WebWorker
    WebWorker postMessage
    // index.js
    var worker = new Worker("Worker.js");
    var request = [];
    worker.onmessage = function(event) {
    var response = event.data.response;
    :
    };
    worker.postMessage({ request: request });
    // Worker.js
    onmessage = function(event) {
    var request = event.data.request;
    postMessage({ response: ["ok"], error: null });
    };

    View Slide

  36. ( )

    View Slide

  37. WebWorker

    View Slide

  38. WebApp
    WebWorker ?
    , ,
    ,
    ,

    View Slide

  39. WebWorker JavaScript
    ?

    View Slide

  40. WebWorker
    ( )

    View Slide

  41. importScripts
    navigator.userAgent, onLine
    JSON, BLOB, FileReader, FileReaderSync
    Timer - setTimeout(), setInterval()
    encodeURIComponent/decodeURIComponent
    TypedArray
    MessageChannel
    WebSQL, WebSQLSync
    WebSocket, XMLHttpRequest

    View Slide

  42. navigator.webkitPersistentStorage
    navigator.webkitTemporaryStorage
    HighPerformanceTimer - performance.now()
    TextEncoder/TextDecoder
    Crypto, Base64(atob, btoa)
    ImageBitmap
    IndexedDB
    WorkerConsole - console.log()
    RequestFileSystem, RequestFileSystemSync
    ES6( Symbol, Set, Map, WeakMap, WeakSet, Promise )

    View Slide

  43. postMessage ?
    Nexus 7(2012) Chrome 0.6ms,
    Mac Chrome 0.02ms
    var worker = new Worker("worker.js");
    var score = 0;
    worker.onmessage = function(event) {
    worker.postMessage(++score);
    };
    setTimeout(function() { worker.postMessage("stop"); }, 10 * 1000);
    // worker.js
    var payload = [];
    var timerID = setInterval(function() {
    postMessage(payload);
    }, 1);
    onmessage = function(event) {
    event.data === "stop" && clearInterval(timerID);
    };

    View Slide

  44. postMessage
    Structured Cloning
    var payload = new Array(big number);
    postMessage(payload);
    1MB (payload)
    32MB payload
    25%
    var MB = 1024 * 1024;
    var payload = new Uint8ClampedArray( 1 * MB); // 無負荷時の 98% の速度で動作
    var payload = new Uint8ClampedArray( 8 * MB); // 無負荷時の 90% の速度で動作
    var payload = new Uint8ClampedArray(32 * MB); // 無負荷時の 25% の速度で動作
    Structured Cloning

    View Slide

  45. Transferable Objects
    postMessage
    (zero-copy)
    Transferable Objects
    var payload = new Array(big number);
    postMessage(payload, [payload]);
    Transferable Objects

    View Slide

  46. WebWorker
    importScript
    JavaScript Prototype
    WebWorker

    View Slide

  47. + Module
    Node.js, Browser, WebWorker
    (function(global) {
    // --- define ----------------------------------------------
    // --- variable --------------------------------------------
    // --- interface -------------------------------------------
    function Class() {
    }
    // --- implement -------------------------------------------
    // --- export ----------------------------------------------
    if (global.process) {
    module.exports = Class;
    }
    global.Class = Class;
    })(this.self || global);
    : Typical JavaScript Module Pattern

    View Slide

  48. WebWorker ?
    iframe

    View Slide

  49. WebWorker

    View Slide

  50. Storage, Cache, Offline
    Storage
    LocalStorage 5MB

    WebSQL
    50MB
    ApplicationCache

    View Slide

  51. LocalStorage + WebSQL
    Base64
    DataURI

    View Slide

  52. Asset Manifest
    304 Not Modified
    HTTP
    1 (SPDY )
    5MB + 5MB

    View Slide

  53. Asset Manifes Sample
    ID URL
    MimeType
    Hash (MD5, SHA1 )
    ,
    {
    "HelloAssetManifest": {
    "url": "asset/scene/Hello.js",
    "hash": "fd2b04",
    "mime": "scene/class",
    "size": 1425,
    "prime": 1
    }
    }

    View Slide

  54. Storage
    Indexed DB + Disk Quota Management API
    10%
    ServiceWorker
    URL

    View Slide


  55. デモ
    1 30MB (140kB jpg x 210 )
    Base64 1 40 50MB
    13 (600 800MB)

    View Slide

  56. SinglePageApplication
    WebSQL LocalStorage
    Asset Manifest
    iframe
    Base64 Doubler
    1
    (Bulk Download)

    View Slide

  57. Doubler
    Base64 ASCII
    SQLite(LocalStorage WebSQL )
    UTF16
    Doubler NULL, BOM,
    UTF16
    Base64 200 250%

    View Slide

  58. Doubler Code Point
    // Doubler.js: UTF16 Safe packer
    // Mobile Browser unavailable UTF16 words:
    // Safari: NULL, BOM
    // Chrome: NULL, BOM, SurrogatePairs
    // Android: NULL
    //
    // Desktop Browser unavailable UTF16 words:
    // Safari: NULL, BOM
    // Chrome: NULL, BOM, SurrogatePairs
    //
    // +- UINT16 -+- Doubler.pack() -+- unpack -+
    // | 0x0000 | 0x0020, 0x8000 | -0x8000 | encode NULL
    // +----------+------------------+----------+
    // | 0x0020 | 0x0020, 0x8020 | -0x8000 | encode 0x20
    // +----------+------------------+----------+
    // | 0xd800 | 0x0020, 0x5800 | +0x8000 | encode SurrogatePairs
    // | : | : | |
    // | 0xdfff | 0x0020, 0x5fff | |
    // +----------+------------------+----------+
    // | 0xfffe | 0x0020, 0x7ffe | +0x8000 | encode BOM
    // | 0xffff | 0x0020, 0x7fff | |
    // +-- Tail --+- Doubler.pack() -+----------+
    // | 0x00 | 0x0020, 0x9000 | -0x9000 | encode Tail byte
    // | : | : | |
    // | 0xff | 0x0020, 0x90ff | |
    // +----------+------------------+----------+

    View Slide

  59. Bulk Download
    GIF
    AssetSprite
    1
    ?
    (SPDY )

    View Slide


  60. View Slide