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.

Avatar for Christian Liebel

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