Hello.

I am Paul Kinlan.

A Developer Advocate for Chrome and the Open Web at Google.

Modern Mobile Bookmarklets with the ShareTarget API

Paul Kinlan

Bookmarklets are an unsung superpower of Desktop Web Browsers. They are not as powerful as Chrome Extensions, they require a user gesture, they don’t have access to browser specific API’s (such as chrome.*), yet I love them. In their simplest form (a Bookmark) they navigate you to a URL; more complex forms (Bookmarklets) navigate to a javascript: URL which means you can run simple automated actions that run in the context of the page, creating functionality that the original developer didn’t get around to creating just yet, just at the click of a button.

Read More
Picture of me smiling.

Paul Kinlan

Trying to make the web and developers better.

RSS Github Medium

Pixel 4XL Infrared sensor via getUserMedia

Paul Kinlan

It’s turns out that you can access the pixel 4 face detection IR camera via normal getUserMedia. The interesting thing is that if you try to do face unlock when this camera is being used (the bit where it throws things on to your face) the system will just flat refuse to do any of the face unlock process and that makes sense. If you want to quickly try this then you can view the demo here.

Read More

Sunset over Tokyo from Shibuya

Paul Kinlan

I was walking past the window in the Office and I saw this rather awesome view.

Read More

Harlech Castle

Paul Kinlan

I love a good Castle. Luckily North Wales is full of amazing Castles. Last week I took the boys to Harlech Castle and we had a grand old time. It’s well maintained and has an amazing history to it. It’s positioned on the top of a hill that has amazing views of Snowdonia and the Irish sea. Unlike Carlisle castle, I didn’t get to ruminate on the impact of Brexit, I just got to look at the awesome views.

Read More

Puppeteer Go🔗

Paul Kinlan

I love Puppeteer - it lets me play around with the ideas of The Headless Web - that is running the web in a browser without a visible browser and even build tools like DOM-curl (Curl that runs JavaScript). Specifically I love scripting the browser to scrape, manipulate and interact with pages.

One demo I wanted to make was inspired by Ire’s Capturing 422 live images post where she ran a puppeteer script that would navigate to many pages and take a screenshot. Instead of going to many pages, I wanted to take many screenshots of elements on the page.

The problem that I have with Puppeteer is the opening stanza that you need to do anything. Launch, Open tab, navigate - it’s not complex, it’s just more boilerplate than I want to create for simple scripts. That’s why I created Puppeteer Go. It’s just a small script that helps me build CLI utilities easily that opens the browser, navigates to a page, performs your action and then cleans up after itself.

Check it out.

const { go } = require('puppeteer-go');

go('https://paul.kinlan.me', async (page) => {
    const elements = await page.$$("h1");
    let count = 0;
    for(let element of elements) {
      try {
        await element.screenshot({ path: `${count++}.png`});
      } catch (err) {
        console.log(count, err);
      }
    }
});

The above code will find the h1 element in my blog and take a screenshot. This is nowhere near as good as Ire’s work, but I thought it was neat to see if we can quickly pull screenshots from canisuse.com directly from the page.

const { go } = require('puppeteer-go');

go('https://caniuse.com/#search=css', async (page) => {
    const elements = await page.$$("article.feature-block.feature-block--feature");
    let count = 0;
    for(let element of elements) {
      try {
        await element.screenshot({ path: `${count++}.png`});
      } catch (err) {
        console.log(count, err);
      }
    }
});
4.png
3.png
2.png
1.png
0.png

Enjoy!

A simple video insertion tool for EditorJS🔗

Paul Kinlan

I really like EditorJS. It’s let me create a very simple web-hosted interface for my static Hugo blog.

EditorJS has most of what I need in a simple block-based editor. It has a plugin for headers, code, and even a simple way to add images to the editor without requiring hosting infrastructure. It doesn’t have a simple way to add video’s to the editor, until now.

I took the simple-image plugin repository and changed it up (just a tad) to create a simple-video plugin (npm module). Now I can include videos easily in this blog.

If you are familar with EditorJS, it’s rather simple to include in your projects. Just install it as follows

npm i simple-video-editorjs

And then just include it in your project as you see fit.

const SimpleVideo = require('simple-video-editorjs');

var editor = EditorJS({
  ...
  
  tools: {
    ...
    video: SimpleVideo,
  }
  
  ...
});

The editor has some simple options that let you configure how the video should be hosted in the page:

  1. Autoplay - will the video play automatically when the page loads
  2. muted - will the video not have sound on by default (needed for autoplay)
  3. controls - will the video have the default HTML controls.

Below is a quick example of a video that is embedded (and showing some of the options).

Anyway, I had fun creating this little plugin - it was not too hard to create and about the only thing that I did was defer the conversion to base64 which simple-images uses and instead just use the Blob URLs.

Test post Video upload

Friendly Project Name Generator with Zeit🔗

Paul Kinlan

I’ve got some ideas for projects that make it easier to create sites on the web - one of the ideas is to make a netlify-like drag and drop interface for zeit based projects (I like zeit but it requires a tiny bit of cli magic to deploy).

This post covers just one small piece of the puzzle: creating project names.

Glitch is a good example of this, when you create a project it gives it a whimsical randomly generated name. The team also created a good dictionary of fairly safe words that combine well (and if you want they have a simple server to host).

So, the side project this Sunday was to create a simple micro-service to generate random project names using Zeit’s serverless-functions and the dictionary from Glitch.

And here it is (code), it’s pretty short and not too complex.

const words = require("friendly-words");

function generate(count = 1, separator = "-") {
  const { predicates, objects } = words;
  const pCount = predicates.length;
  const oCount = objects.length;
  const output = [];

  for (let i = 0; i < count; i++) {
    const pair = [predicates[Math.floor(Math.random() * pCount)], objects[Math.floor(Math.random() * oCount)]];
    output.push(pair.join(separator));
  }

  return output;
}

module.exports = { generate }

If you don’t want to include it in your project directly, you can use the HTTP endpoint to generate random project names (in the form of “X-Y”) by making a web request to https://friendly-project-name.kinlan.now.sh/api/names, which will return something like the following.

["momentous-professor"]

You can also control how many names to generate with the a query-string parameter of count=x, e.g. https://friendly-project-name.kinlan.now.sh/api/names?count=100

["melon-tangerine","broad-jury","rebel-hardcover","far-friend","notch-hornet","principled-wildcat","level-pilot","steadfast-bovid","holistic-plant","expensive-ulna","sixth-gear","political-wrench","marred-spatula","aware-weaver","awake-pair","nosy-hub","absorbing-petunia","rhetorical-birth","paint-sprint","stripe-reward","fine-guardian","coconut-jumbo","spangle-eye","sudden-euphonium","familiar-fossa","third-seaplane","workable-cough","hot-light","diligent-ceratonykus","literate-cobalt","tranquil-sandalwood","alabaster-pest","sage-detail","mousy-diascia","burly-food","fern-pie","confusion-capybara","harsh-asterisk","simple-triangle","brindle-collard","destiny-poppy","power-globeflower","ruby-crush","absorbed-trollius","meadow-blackberry","fierce-zipper","coal-mailbox","sponge-language","snow-lawyer","adjoining-bramble","deserted-flower","able-tortoise","equatorial-bugle","neat-evergreen","pointy-quart","occipital-tax","balsam-fork","dear-fairy","polished-produce","darkened-gondola","sugar-pantry","broad-slouch","safe-cormorant","foregoing-ostrich","quasar-mailman","glittery-marble","abalone-titanosaurus","descriptive-arch","nickel-ostrich","historical-candy","mire-mistake","painted-eater","pineapple-sassafras","pastoral-thief","holy-waterlily","mewing-humor","bubbly-cave","pepper-situation","nosy-colony","sprout-aries","cyan-bestseller","humorous-plywood","heavy-beauty","spiral-riverbed","gifted-income","lead-kiwi","pointed-catshark","ninth-ocean","purple-toucan","tundra-cut","coal-geography","icy-lunaria","agate-wildcat","respected-garlic","polar-almandine","periodic-narcissus","carbonated-waiter","lavish-breadfruit","confirmed-brand","repeated-period"]

You can control separator with the a query-string parameter of separator. i.e, separator=@ , e.g. https://friendly-project-name.kinlan.now.sh/api/names?separator=@

["handsomely@asterisk"]

A very useful aspect of this project is that if a combination of words tends towards being offensive, it is easy to update the Glitch repo to ensure that it doesn’t happen again.

Assuming that the project hosting doesn’t get too expensive I will keep the service up, but feel free to clone it yourselves if you ever want to create a similar micro-service.

Live example

What follows is a super quick example of the API in action.

const render = (promise, elementId) => {
  promise.then(async(response) => {
    const el = document.getElementById(elementId);
    el.innerText = await response.text();
  })
};


onload = () => {
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names"), "basic");
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names?count=100"), "many");
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names?separator=@"), "separator");
}

Single response


Many resposnses


Custom separators









  
        
      

Frankie and Bennys: Pay for your meal via the web

Paul Kinlan

Whenever I see a restaurant say that you can pay on mobile, I always check it out, mostly so I can bemoan the fact that you need to use an app. Imagine my surprise when the QR code lead to a web-based payments flow….. and it worked. Awesome work Frankie and Benny’s! At this point, I did select Google Pay, but it didn’t work (email internally sent!

Read More

Podroll

Adding "dark mode" to my blog

Paul Kinlan

I saw Jeremy Keith’s post about adding dark mode to his blog and it seemed simple, so I decided to give it a whirl. Here is the diff of the work for all to see. It was surprisingly easy (outside of silly errors on my part). There was a small refactor to support CSS variables and ensuring I have fallback if there’s a browser that doesn’t support CSS custom properties, but that is about it.

Read More

Using Web Mentions in a static site (Hugo)

Paul Kinlan

My blog is an entirely static site, built with Hugo and hosted with Zeit. This is a great solution for me, a simple blog has a pretty simple deployment process and it loads blazingly fast. Statically generated sites do have some drawbacks, the largest is when you need anything dynamic to be integrated into your page (comments for example). Not being able to easily host dynamic content will mean that you end up relying on 3rd party JavaScript that will then get full access to your page and you won’t know what it is doing - it could be tracking your users or slowing down your page load.

Read More

Creating a pop-out iframe with adoptNode and "magic iframes"

Paul Kinlan

Update: 8th October - Significant issues with this doc. I caught up with Jake Archibald about this post because I thought I had something novel, during the conversation we uncovered a lot of things that make some of this post invalid, and I also learnt a lot in the process that I don’t think most developers know. Calling .append() and .appendChild() adopt the node. This makes the usage of adoptNode in this instance useless because the append Algorithm ensures that the node is adopted.

Read More

Meatspace Augmented Reality: From Chester to Nagoya

Paul Kinlan

Some thoughts on AR after finding some during my travels. TL;DR - cheaper content creation and better discovery tools are needed.

Read More

Photos from Carlisle Castle

Paul Kinlan

I recently went on holiday with the boys and we swung past Carlisle Castle (birthplace of the world rebound Jake Archibald). It is one of the better castles that we’ve been to in the UK and I would heartily recommend spending some time visiting it if you are in the area. I didn’t how significant the role was that Carlisle Castle played in the history of the England and Scotland, and it was great to find out more whilst we were there.

Read More

Idle observation: Indexing text in images

Paul Kinlan

I was out with the boys in Llangollen the other day (it’s a beautiful town) and I was taking pictures of the informational signs containing some of the history of the area so that I could read it later, and I thought that I would look on the web to see if the information was available for more than just the people walking past the sign - and it’s not. I then got thinking about the leaflets, the content in them is nearly impossible to find on the web.

Read More

Liverpool World Museum

Paul Kinlan

I took the kids to the Liverpool World History Museum the other week, it was pretty neat. The Space and Time section has not changed in about 30 years, a large section of the Bug enclosure was closed off, and the Aquarium seemed a tad smaller than I remember. The Egyptian section was open (it wasn’t when I last went) and it was rather awesome.

Read More

Bookstore - Llangollen

Paul Kinlan

I love this place, it’s on top of a cafe in Llangollen. I came here with my grandparents nearly 30 years ago and it’s pretty much the same now. My only wish is that there was even more Commix books - I swear there was a heap more when I was a kid. Check it out

Read More

Webmention.app🔗

Paul Kinlan

I love the idea of Webmentions, yet I’ve not had the time to implement it on my site. At a high-level web mentions let you comment, like and reply to other content on the web and have it be visible to that content without being centralised with tools like Disqus (which I am keen to remove from my site).

Web Mentions are split in to two components, the sender and the receiver. The receiver is the site that I am writing a post about and they might have something on their site that shows inbound links or reactions to their blog; and the sender is, well, me. I need to let the remote site that I have written or reacted to some content that they have created.

The rather awesome Remy Sharp created webmention.app to solve one part of the problem: sending pings. Remy’s tool  makes it easy to send ‘pings’ to potential receivers that I have linked to, by simply calling a CLI script.

I host my blog using Zeit using Hugo and the static-builder tool, so it was relatively trivial for me to add in support for webmention app. I just npm i webmention and then call the CLI version of the tool from my build.sh file - it really is that simple.

Now when I create a post, it should send a quick ping to all new URL’s that I have created some content about their site.

Creating a commit with multiple files to Github with JS on the web

Paul Kinlan

My site is entirely static. It’s built with Hugo and hosted with Zeit. I’m pretty happy with the setup, I get near instant builds and super fast CDN’d content delivery and I can do all the things that I need to because I don’t have to manage any state. I’ve created a simple UI for this site and also my podcast creator that enables me to quickly post new content to my statically hosted site.

Read More