Hi, I'm James.
I make websites.
Iʼm currently leading the talented dev team at Superrb where I build awesome websites and interactive experiences like these 
Turns out, the big names have .
My work has been recognised by some of the industryʼs top players.- Awwwards- Honorable Mention
 
- Awwwards- Honorable Mention
- Nominated for 2022 E-commerce Site of the Year
 - Typewolf- Site of the Day
 
- Awwwards- Site of the Day
- Developer Award
- Nominated for 2019 Developer Site of the Year
 - Creative Pool- Nominated for 2019 Annual Web Shortlist
 - CSS Design Awards- Site of the Day
- Best Innovation
- Best UI Design
- Best UX Design
 
Some things are to keep to myself.
I build open source tools, because good ideas are better when shared./** * LiveNodeList * * An alternative to document.querySelector * that monitors the DOM for changes */
import { LiveNodeList } from 'live-node-list'
const items = new LiveNodeList('.my-selector')
// Attach an event listener to each item
// in the node list. The listener will automatically
// be attached to any new elements matching the
// selector when they are added to the DOM
items.addEventListener('click', (e) => {
  alert(`Clicked! ${e.target.id}`)
})
// Listen for changes to the node list
// (e.g. when elements are added or removed)
// and apply updates to the new items
items.on('update', (newItems, oldItems) => {
  newItems.forEach((item) => {
    item.setAttribute('aria-label', 'New item')
  })
})
/** * Consumer * * A simple and lightweight tool to create an * ORM-like consumer for any JSON REST API */
import consume from 'api-consumer'
const api = consume('https://api.example.com')
// GET https://api.example.com/users/123/comments
const userComments = await api.users[123].comments.all()
// POST https://api.example.com/users
const user = await api.users.create({
  name: 'Joe Bloggs',
  email: 'joe@bloggs.com'
})
// GET https://api.example.com/users/1
const user = await api.users.find(1)
user.name = 'Joseph Bloggs'
// PUT https://api.example.com/users/1
await user.save()
/** * ZUnit * * A powerful testing framework and * assertion library for ZSH projects */
#!/usr/bin/env zunit
@test 'App should run' {
  run my-app
  assert $state equals 0
  assert "$output" same_as "It worked!"
}
@test 'App fails with invalid arg' {
  run my-app --invalid-arg
  assert $state equals 127
  assert "$output" same_as "Invalid argument: --invalid-arg"
}
/** * Async * * A simple PHP library for creating asynchronous processes, * and handling inter-process communication via sockets. */
<?php
use Superrb\Async\Handler;
// Create the handler process
$handler = new Handler(function(int $i): bool {
  $this->send('Hi from process '.$i);
  return true;
});
// Launch multiple processes concurrently
for ($i = 0; $i < 10; $i++) {
  $handler->run($i);
}
// Wait for completion, and check output of each process
$handler->waitAll();
foreach($handler->getMessages() as $message) {
  log($message);
}
/** * Phillip * * Meet Phillip, the newest member of your test team. * A PHP testing framework for the 21st century */
<?php
test('Does 1 equal 1', function($t) {
  if (1 === 1) {
    return $t->pass();
  }
  return $t->fail('1 does not equal 1');
});
/** * Magic Roundabout * * A tiny JavaScript carousel. * */
const magicRoundabout = new MagicRoundabout(
  '#your-element',
  {
    auto: false,
    buttons: true,
    center: false,
    click: true,
    delay: 10000,
    draggable: false,
    keys: true,
    limit: true,
    loop: true,
    onChange: (slideshow) => {},
    touch: true,
    scroll: true,
    vertical: false
  }
)




