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

Making of http://paint.js.org - a Web Component...

Making of http://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, Christian Liebel shows you the critical parts of how http://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

December 07, 2022
Tweet

More Decks by Christian Liebel

Other Decks in Programming

Transcript

  1. 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
  2. Lit @customElement('paint-tool-box') export class ToolBox { render(): TemplateResult { return

    html` ${tools.map( (tool) => html`<paint-tool .tool=${tool} title="${tool.tooltip}" class="${this.drawingContext?.tool === tool ? 'active' : ''} ${tool.instance ? '' : 'unavailable'}" @pointerup="${() => this.selectTool(tool)}" ></paint-tool>`, )} `; } } Making of paint.js.org A Web Component-based Productivity PWA Web Components and Architecture
  3. 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
  4. 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
  5. 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)
  6. 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
  7. 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
  8. Browser Making of paint.js.org A Web Component-based Productivity PWA Capabilities

    navigator.share({ url: 'http://example.com' }); ShareIntent DataTransferManager … NSSharingServicePicker
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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