$30 off During Our Annual Pro Sale. View Details »

Making of paint.js.org—a Web Component-based Productivity PWA

Making of paint.js.org—a Web Component-based Productivity PWA

Progressive Web Apps and the new powerful web APIs provided by Project Fugu allow developers to implement desktop-class productivity apps using web technologies. In this session, Thinktecture's Christian Liebel shows you the critical parts of how paint.js.org was made, a remake of the productivity app dinosaur Microsoft Paint. It runs great as a standalone application, and since it is based on Web Components, it can even be embedded into other applications. And since everything is web-based, it runs on all operating systems, desktop or mobile, not just Windows 95.

Christian Liebel
PRO

June 14, 2022
Tweet

More Decks by Christian Liebel

Other Decks in Programming

Transcript

  1. Making of paint.js.org
    A Web Component-based Productivity
    PWA
    Christian Liebel
    @christianliebel
    Consultant

    View Slide

  2. Hello, it’s me.
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Christian Liebel
    Twitter:
    @christianliebel
    Email:
    christian.liebel
    @thinktecture.com
    Angular & PWA
    Slides:
    thinktecture.com
    /christian-liebel

    View Slide

  3. https://paint.js.org
    – Productivity app
    – Draw images
    – Lots of actions & tools
    – Installable
    – Read/save files
    – Copy/paste images
    from/to clipboard
    – Share files to other apps
    – Register for file extensions
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Demo

    View Slide

  4. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  5. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  6. Web Components


    – The web’s native component
    model
    – Easy interop
    – Very basic: No data binding,
    dependency injection, …
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  7. Related APIs
    Custom
    Elements API
    Definition of custom
    HTML elements
    Interaction via custom
    DOM attributes,
    properties, and events
    Shadow DOM
    Can prevent DOM
    access from outside
    Can prevent CSS
    manipulation from
    outside
    HTML
    Templates
    (not used in this
    demo)
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  8. Lit
    – Provided by Google
    – Lightweight library (5 KB)
    – Custom lifecycle on top of Web
    Components
    – Tagged template literals for HTML
    and CSS to prevent XSS attacks
    including support for data binding
    – TypeScript decorators for
    component registration and
    attribute/property declaration
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  9. Lit
    @customElement('paint-tool-box')
    export class ToolBox {
    render(): TemplateResult {
    return html`
    ${tools.map(
    (tool) => html`class="${this.drawingContext?.tool === tool ? 'active' : ''}
    ${tool.instance ? '' : 'unavailable'}"
    @pointerup="${() => this.selectTool(tool)}"
    >`,
    )}
    `;
    }
    }
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  10. Web Components
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  11. Store Pattern
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  12. Embedded
    https://node-projects.github.io/web-component-designer-demo/index.html
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Web Components and Architecture

    View Slide

  13. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  14. Canvas
    – Plain bitmap for the web
    – Cross-platform, hardware-
    accelerated graphics
    operations
    – Supports different contexts
    (2D, 3D: WebGL, WebGL 2.0)
    – Supported on all evergreen
    browsers and on IE 9+
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Canvas and Input

    View Slide

  15. Canvas 2D Context
    fillRect(x, y, width, height)
    strokeRect(x, y, width, height)
    beginPath()
    moveTo(x, y)
    lineTo(x, y)
    fill()
    stroke()
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Canvas and Input

    View Slide

  16. Pointer Events
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Canvas and Input
    Users nowadays use different
    input methods, cross-platform
    apps should cover all of them
    Pointer Events offer an
    abstract interface to catch all
    input methods (pointerdown,
    pointermove, pointerup)
    event.offsetX/event.offsetY
    contain the pointer’s position
    relative to the listener

    View Slide

  17. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  18. A Web Component-based Productivity PWA
    Making of paint.js.org
    Responsive Linkable Discoverable Installable App-like
    Connectivity
    Independent
    Fresh Safe Re-engageable Progressive

    View Slide

  19. Making of paint.js.org
    A Web Component-based Productivity PWA
    Web App
    Manifest
    Service
    Worker

    View Slide

  20. Web App Manifest
    Distinguishes Web Apps from
    Websites
    JSON-based file containing
    metadata for apps only
    Apps can be identified by search
    engines, app store providers, etc.
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Offline Capability and Installability

    View Slide

  21. manifest.webmanifest
    {
    "short_name": "Paint",
    "name": "Paint Workshop",
    "theme_color": "white",
    "icons": [{
    "src": "icon.png",
    "sizes": "512x512"
    }],
    "start_url": "/index.html",
    "display": "standalone",
    "shortcuts": [/* … */]
    }
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Offline Capability and Installability
    Names
    Icons
    Display Mode
    Shortcuts
    Start URL
    Theme color (status bar/window bar)

    View Slide

  22. Service Worker
    JavaScript snippet executed in an
    own thread, registered by the website
    Acts as a controller, proxy, or
    interceptor
    Has a cache to store responses (for
    offline availability and performance)
    Can wake up even when the website
    is closed and perform background
    tasks (e.g., push notifications or sync)
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Offline Capability and Installability

    View Slide

  23. Service Worker
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Offline Capability and Installability
    Service
    Worker
    Internet
    Website
    HTML/JS
    Cache
    fetch

    View Slide

  24. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  25. Making of paint.js.org
    A Web Component-based Productivity PWA

    View Slide

  26. Project Fugu
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Capabilities
    »Let’s bring the web
    back – API by API«
    Thomas Steiner, Google

    View Slide

  27. Making of paint.js.org
    A Web Component-based Productivity PWA
    Capabilities
    https://goo.gle/fugu-api-tracker

    View Slide

  28. Browser
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Capabilities
    navigator.share({ url: 'http://example.com' });
    ShareIntent DataTransferManager

    NSSharingServicePicker

    View Slide

  29. Async Clipboard API
    Allows reading from/writing to
    the clipboard in an
    asynchronous manner (UI won’t
    freeze during long-running
    operations)
    Reading from the clipboard
    requires user consent first
    (privacy!)
    Supported by Chrome, Edge
    and Safari
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Copy and Paste

    View Slide

  30. Async Clipboard API
    const btnCopy = document.querySelector('#copy');
    btnCopy.addEventListener('click', async () => {
    const blob = await toBlob(canvas);
    await navigator.clipboard.write([
    new ClipboardItem({[blob.type]: blob})
    ]);
    });
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Copy and Paste

    View Slide

  31. Async Clipboard API
    const btnPaste = document.querySelector('#paste');
    btnPaste.addEventListener('click', async () => {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
    for (const type of clipboardItem.types) {
    if (type === 'image/png') {
    const blob = await clipboardItem.getType(type);
    const image = await getImage(blob);
    ctx.drawImage(image, 0, 0);
    }
    }
    }
    });
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Copy and Paste

    View Slide

  32. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  33. File System Access API
    Some applications heavily rely
    on working with files (e.g.
    Visual Studio Code, Adobe
    Photoshop, …)
    File System Access API allows
    you to open, save and override
    files and directories
    Supported by Chrome, Edge
    Making of paint.js.org
    A Web Component-based Productivity PWA
    File Access and File Handling

    View Slide

  34. File System Access API
    btnSave.addEventListener('click', async () => {
    const blob = await toBlob(canvas);
    const handle = await window.showSaveFilePicker(fileOptions);
    const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
    });
    Making of paint.js.org
    A Web Component-based Productivity PWA
    File Access and File Handling

    View Slide

  35. File System Access API
    btnOpen.addEventListener('click', async () => {
    const [handle] = await window.showOpenFilePicker(fileOptions);
    const file = await handle.getFile();
    const image = await getImage(file);
    ctx.drawImage(image, 0, 0);
    });
    Making of paint.js.org
    A Web Component-based Productivity PWA
    File Access and File Handling

    View Slide

  36. File Handling API
    Register your PWA as a
    handler for file extensions
    Requires installing the
    application first
    Declare supported extensions
    in Web App Manifest and add
    imperative code to your
    application logic
    Making of paint.js.org
    A Web Component-based Productivity PWA
    File Access and File Handling

    View Slide

  37. File Handling API
    "file_handlers": [{
    "action": "/index.html",
    "accept": {
    "image/png": [".png"]
    }
    }]
    Making of paint.js.org
    A Web Component-based Productivity PWA
    File Access and File Handling

    View Slide

  38. File Handling API
    if ('launchQueue' in window) {
    launchQueue.setConsumer(async params => {
    const [handle] = params.files;
    if (handle) {
    const file = await handle.getFile();
    const image = await getImage(file);
    ctx.drawImage(image, 0, 0);
    }
    });
    }
    Making of paint.js.org
    A Web Component-based Productivity PWA
    File Access and File Handling

    View Slide

  39. Web
    Components
    and Architecture
    Canvas and
    Input
    Offline
    Capability and
    Installability
    Copy and Paste
    File Access and
    File Handling
    Dark Mode
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Agenda

    View Slide

  40. CSS Custom Properties
    – Also known as “CSS variables”
    – Cascade even through
    Shadow DOM boundaries, i.e.
    they can be accessed by
    subordinate components
    – Paint.js.org defines the
    Windows 95 color scheme on
    app root level
    :host {
    --button-face: rgb(192 192 192);
    --button-light: white;
    --button-dark: rgb(128 128 128);
    --button-darker: black;
    --button-text: black;
    }
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Dark Mode

    View Slide

  41. prefers-color-scheme CSS Media Feature
    – The prefers-color-scheme CSS media feature indicates which color
    scheme the user prefers
    – Takes two values:
    – light, if the user prefers a dark-on-light color scheme (or didn’t
    actively make a decision)
    – dark, if the user prefers a light-on-dark color scheme
    – Preference is usually inherited form the operating system’s settings
    – Changes are automatically reflected (e.g., when the operating system
    switches between light and dark mode based on time)
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Dark Mode

    View Slide

  42. CSS-Only
    Light Mode
    :host {
    --button-face: rgb(192 192 192);
    --button-light: white;
    --button-dark: rgb(128 128 128);
    --button-darker: black;
    --button-text: black;
    }
    Dark Mode
    @media (prefers-color-scheme: dark) {
    :host {
    --button-face: rgb(64 64 64);
    --button-light: rgb(128 128 128);
    --button-dark: rgb(32 32 32);
    --button-text: white;
    }
    }
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Dark Mode

    View Slide

  43. Making of paint.js.org
    A Web Component-based Productivity PWA
    Dark Mode

    View Slide

  44. Web Components: Very robust, works consistently across evergreen
    browsers, perfect for integration scenarios.
    Lit: Shares basic concepts with other frameworks/libraries (such as
    Angular), but is much more lightweight. Paint.js.org is smaller (=
    transferred bytes) than the Windows 95 of Paint (320K)!
    Capabilities: Powerful APIs available on Chromium and WebKit-based
    browsers, fallbacks are used for other browsers.
    Conclusion: Successful project! 🥳 You can perfectly implement web-
    based (= cross-platform), desktop-class productivity applications.
    Making of paint.js.org
    A Web Component-based Productivity PWA
    Summary

    View Slide

  45. Making of paint.js.org
    A Web Component-based Productivity PWA
    Outlook

    View Slide

  46. Thank you
    for your kind attention!
    Christian Liebel
    @christianliebel
    [email protected]

    View Slide