Recent posts (max 10) - Browse or Archive for more

Blinds Tilt Mechanism Repair

We have a large faux-wood blind on our dining room window. The window pane itself is 70"x70"; which makes for a great view. However, the tilt mechanism stopped working in fairly short order. The tilt mechanism uses a pull-cord based mechanism which is no longer offered in blinds. I replaced the mechanism the first time it failed, but when it failed the second time in much the same way, I could no longer find a replacement for the parts. The original mechanism failed because the interface between the cord spool and the shaft driving the worm gear which drove the tilting of the blinds had worn, become loose, and allowed the cord spool to rotate without turning the worm gear shaft. The replacement mechanism failed in a different place; it had a bushing to adapt the sqare rod that runs the length of the blinds to a hexagonal through-hole in the driving gear. That bushing was made of plastic and had worn to the point that the drive gear could rotate without rotating the square rod.

The original tilt mechanism was made largely from metal components, while the replacement I had purchased was largely plastic. Examining them both, I determined that it would be more straight-forward to machine a new pully for the original mechanism than to machine a drive gear for the replacement mechanism. The original pully was made of nylon; I chose to machine a replacement pully from aluminum bar stock.

Cutting the main profile of the spool body:

1-cutting-main-profile.jpg 2-cutting-deeper.jpg

And the conical recess in the spool: 3-conical-recess.jpg

Cutting the spool off the stock: 4-cutoff-conical.jpg 5-cutoff-flat.jpg

Milled the slot for the worm gear shaft and the holes required for the threading the pull cord through: 6-milled-slot-conical.jpg 7-milled-slot-flat.jpg

Installed in the blinds: 8-installed.jpg 9-installed-closeup.jpg

This has held up well over the past 8 months, and it was gratifying to be able to repair something when replacement parts were no longer available.

Building an electronics organizer

The number of tablets, laptops, phones, ... let's just say "electronic devices" around the house has increased noticeably over the years, and finding that we had them haphazardly piled upon the end-table, ready to cascade off into a pile of mutual destruction, I decided we needed a mechanism for organizing them and defining an official location where they belong.

Design:

Given that I wanted room for six devices up to 1" thick, that meant 7 vertical boards, 3/4" thick each, yielding a base board 11-1/4" long. Allowing 1/4" for kerf leaves me with some room for error, so that leaves 60.5" of material from which to cut 7 uprights. That will mean 6 kerfs, giving me 59" of remaining material to allocate among the uprights. Making the upgrights equal lengths gives a height a little under 8.5". Rather than doing that, I opted to make the upgrights 9", 8.5", 8", 8", 8", 8.5", and 9" tall, giving a more interesting shape to the final product and giving nice "round" numbers for the lengths.

Materials:

  • 1x 6-foot, 1x8 poplar lumber
  • 14x 1-1/4" pocket-hole screws
  • wood stain

Tools:

  • pocket-hole jig
  • drill motor
  • tablesaw with fence and miter gauge
  • mitersaw

(Ideally, anyway; I actually made do with the tablesaw, but some of the cuts suffered for it.)

  • bench sander
  • several bar clamps with rubber feet

Cutting:

I cut the 11-1/4" base, two 9" uprights, two 8.5" uprights, and three 8" uprights. Then drilled two pocket-holes in each of the uprights, but _not_ in the base. I slightly rounded the corners of the wood on the bench sander, and touched up a couple of the cut faces where I had accidentally wiggled the board and gotten a less-than-perfect cut.

cut-and-drilled.jpg

Staining:

With a brush, I applied stain to one side of each of the pieces, wiped them down with a rag, applied stain to the edges (except the bottom edges of the uprights since those would not be visible) and wiped them down again, and then applied stain to the reverse side of each upright and wiped them all down. Then allowed them to dry overnight.

stained.jpg

Assembly:

The gaps between the uprights are too narrow to get a drill motor between them, so all the uprights have the pockethole screws facing the same direction, and I screwed them to the base in order from one end. Using the table saw as a clamping structure worked out very well for keeping the uprights aligned with the base and at right angles to it.

assembly-upright-3.jpg

assembled.jpg

Installed:

And here it is placed on a deep shelf with powerstrips behind it for the wall-warts and chargers.

installed.jpg

All-in-all, this worked out very well for what I was attempting to solve, and it came together with a lot less time invested than I had expected.

More fun with the bash prompt

A few years ago, I posted some fun Bash prompt tools, part of which was adding emoticons to the prompt based on the previous command's exit code. I figured it was time to revisit that bit of fun with a couple of enhancements.

First, a bit of code cleanup so color choices are more obvious, and add faces for SIGILL and SIGKILL.

#!/bin/bash
# source this
function prompt_smile () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$green
        face=":)"
    elif [ $retval -eq 1 ]; then
        color=$red
        face=":("
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=":|"
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        face=":-&"
    elif [ $retval -eq 137 ]; then # KILL
        color=$red
        face="X_X"
    elif [ $retval -eq 139 ]; then # SEGV
        color=$red
        face=">_<"
    elif [ $retval -eq 143 ]; then # TERM
        color=$red
        face="x_x"
    else
        color=$red
        face="O_o"
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Download

When sourced into your shell with . promptsmile.sh, you get results like this:

bash-4.4$ . promptsmile.sh
bash-4.4$ :) false
bash-4.4$ :( true
bash-4.4$ :) sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 26699
[2] 26700
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ :| sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 26709
[2] 26710
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ :-& sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 26776
[2] 26777
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ X_X sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 26788
[2] 26789
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ >_< sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 26852
[2] 26853
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ x_x (exit 4)
bash-4.4$ O_o true
bash-4.4$ :) exit

One bit of feedback I received was that the use of :) vs x_x meant that command prompts would shift by a character, and it would be better to have all the emoticons be of the same width. So if you prefer your faces all the same width, promptsmile-3wide.sh gives you more consistent line lengths:

#!/bin/bash
# source this
function prompt_smile () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$green
        face=":-)"
    elif [ $retval -eq 1 ]; then
        color=$red
        face=":-("
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=":-|"
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        face=":-&"
    elif [ $retval -eq 137 ]; then # KILL
        color=$red
        face="X_X"
    elif [ $retval -eq 139 ]; then # SEGV
        color=$red
        face=">_<"
    elif [ $retval -eq 143 ]; then # TERM
        color=$red
        face="x_x"
    else
        color=$red
        face="O_o"
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Download

Which looks like this:

bash-4.4$ . promptsmile-3wide.sh
bash-4.4$ :-) false
bash-4.4$ :-( true
bash-4.4$ :-) sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 26914
[2] 26915
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ :-| sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 26925
[2] 26926
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ :-& sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 26991
[2] 26992
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ X_X sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 27001
[2] 27002
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ >_< sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 27065
[2] 27066
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ x_x (exit 4)
bash-4.4$ O_o true
bash-4.4$ :-) exit

For that old-school style, the text-based emoticons work well, but systems that support emojis are becoming rather common-place, so we can use UTF-8 to get little emotional faces in our prompts:

#!/bin/bash
# source this
function prompt_emoji () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$yellow
        face=$'\360\237\230\200' # :D
    elif [ $retval -eq 1 ]; then
        color=$yellow
        face=$'\360\237\230\246' # :(
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=$'\360\237\230\220' # :|
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        #face=$'\360\237\244\242' # nauseated # get a rectangle in Konsole
        face=$'\360\237\230\223' # cold sweat face
    elif [ $retval -eq 137 ]; then # KILL
        color=$yellow
        face=$'\360\237\230\265' # x_x
    elif [ $retval -eq 139 ]; then # SEGV
        #color=$yellow
        #face=$'\360\237\244\250' # Face with one eyebrow raised # get a rectangle in Konsole
        color=$red
        face=$'\360\237\230\240' # Angry face
    elif [ $retval -eq 143 ]; then # TERM
        color=$yellow
        face=$'\360\237\230\243' # >_<
    else
        color=$yellow
        face=$'\360\237\230\245' # ;(
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_emoji) "

Download

Which will give something maybe like this. The way the faces are rendered will depend on your terminal. For Konsole, these are simple line art; for Gnome-terminal some match Konsole, others have a more blob-like shape; and here they're rendered by your browser.

bash-4.4$ . promptemoji.sh
bash-4.4$ 😀 false
bash-4.4$ 😦 true
bash-4.4$ 😀 sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 27143
[2] 27144
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ 😐 sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 27154
[2] 27155
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ 😓 sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 27220
[2] 27221
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ 😵 sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 27232
[2] 27233
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ 😠 sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 27295
[2] 27296
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ 😣 (exit 4)
bash-4.4$ 😥 true
bash-4.4$ 😀 exit

Beyond that, you'll find that your terminal may render a different subset of emojis than what mine does. I found a useful site for finding emojis with octal UTF-8 which makes it easy to update promptemoji.sh with something that suits your particular set of software.

And for ANSI colors, you may find this reference handy.

Go then, and liven up your own bash prompts, even more!

LDraw Parts Library 2019-02 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-02 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201902-ec1.fc29.src.rpm

ldraw_parts-201902-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201902-ec1.fc29.noarch.rpm
ldraw_parts-models-201902-ec1.fc29.noarch.rpm

LeoCAD 19.07.1 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 19.07.1 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-19.07.1-1ec1.fc29.x86_64.rpm

leocad-19.07.1-1ec1.fc29.src.rpm

Grid-based Tiling Window Management

Many years ago, a coworker of mine showed me Window's "quick tiling" feature, where you would press Window-LeftArrow or Window-RightArrow to snap the current window to the left or right half of the screen. I then found that KDE on Linux had that same feature and the ability to snap to the upper-left, lower-left, upper-right, or lower-right quarter of the screen. I assigned those actions to the Meta-Home, Meta-End, Meta-PgUp, and Meta-PgDn shortcuts. (I'm going to use "Meta" as a generic term to mean the modifier key that on Windows machines has a Windows logo, on Linux machines has a Ubuntu or Tux logo, and Macs call "command".) Being able to arrange windows on screen quickly and neatly with keyboard shortcuts worked extremely well and quickly became a capability central to how I work.

Then I bought a 4K monitor.

With a 4K monitor, I could still arrange windows in the same way, but now I had 4 times the number of pixels. There was room on the screen to have a lot more windows that I could see at the same time and remain readable. I wanted a 4x4 grid on the screen, with the ability to move windows around on that grid, but also to resize windows to use multiple cells within that grid.

Further complicating matters is the fact that I use that 4K monitor along with the laptop's !FullHD screen which is 1920x1080. Dividing that screen into a 4x4 grid would be awkward; I wanted to retain a 2x2 grid for that screen, and keep a consistent mechanism for moving windows around on that screen and across screens.

KDE (Linux)

Unfortunately, KDE does not have features to support such a setup. So I went looking for a programatic way to control window size and placement on KDE/X11. I found three commandline tools that among them offered primitives I could build upon: xdotool, wmctrl, and xprop.

My solution was to write a Python program which took two arguments: a command and a direction.

The commands were 'move', 'grow', and 'shrink', and the directions 'left', 'right', 'up', and 'down'. And one additional command 'snap' with the location 'here' to snap the window to the nearest matching grid cells. The program would identify the currently active window, determine which grid cell was a best match for the action, and execute the appropriate xdotool commands. Then I associated keyboard shortcuts with those commands. Meta-Arrow keys for moving, Meta-Ctrl-Arrow keys to grow the window by a cell in the given direction, Meta-Shift-Arrow to shrink the window by a cell from the given direction, and Meta-Enter to snap to the closest cell.

system-settings-config.png

Conceptually, that's not all that complicated to implement, but in practice:

Window geometry has to be adjusted for window decorations. But there appears to be a bug with setting the position of a window. The window coordinates used by the underlying tools for setting and getting the geometries do not include the frame, except for setting the position of the window, on windows that have a 'client' of the machine name instead of N/A. Getting the position, getting the size, and setting the size, all use the non-frame values. Windows with a client of N/A use the non-frame values for everything. A border width by title bar height offset error for only some of the windows proved to be a vexing bug to track down.

The space on a secondary monitor where the taskbar would be is also special, even if there is no task bar on that monitor; attempting to move a window into that space causes the window to shift up out of that space, so there remains an unused border on the bottom of the screen. Annoying, but I have found no alternative.

Move operations are not instantaneous, so setting a location and immediately querying it will yield the old coordinates for a short period.

A window which is maximized does not respond to the resize and move commands (and attempting it will cause xdotool to hang for 15 seconds), so that has to be detected and unmaximized.

A window which has been "Quick Tiled" using KDE's native quick-tiling feature acts like a maximized window, but does not set the maximized vert or maximized horz state flags, so cannot be detected with xprop, and to get it out of the KDE quick tiled state, it must be maximized and then unmaximized. So attempting to move a KDE quick tiled window leads to a 15 second pause, then the window maximizing briefly, and then resizing to the desired size. In practice, this is not much of an issue since my tool has completely replaced my use of KDE's quick-tiling.

OS X

I recently whined to a friend about not having the same window management setup on OS X; and he pointed me in the direction of a rather intriguing open source tool called Hammerspoon which lets you write Lua code to automate tasks in OS X and can assign keyboard shortcuts to those actions. That has a grid module that offers the necessary primitives to accomplish the same goal.

After installing Hammerspoon, launching it, and enabling Accessibility for Hammerspoon (so that the OS will let it control application windows), use init.lua as your ~/.hammerspoon/init.lua and reload the Hammerspoon config. This will set up the same set of keyboard shortcuts for moving application windows around as described in the KDE (Linux) section. For those who use OS X as their primary system, that set of shortcuts are going to conflict with (and therefore override) many of the standard keyboard shortcuts. Changing the keyboard shortcuts to add the Option key as part of the set of modifiers for all of the shortcuts should avoid those collisions at the cost of either needing another finger in the chord or putting a finger between the Option and Command keys to hit them together with one finger.

I was pleasantly surprised with how easily I could implement this approach using Hammerspoon.

Demo

Simple demo of running this on KDE:

(And that beautiful background is a high resolution photo by a friend and colleague, Sai Rupanagudi.)

LDraw Parts Library 2019-01 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-01 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201901-ec1.fc29.src.rpm

ldraw_parts-201901-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201901-ec1.fc29.noarch.rpm
ldraw_parts-models-201901-ec1.fc29.noarch.rpm

LeoCAD 18.02 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged the 18.02 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-18.02-1ec1.fc29.x86_64.rpm

leocad-18.02-1ec1.fc29.src.rpm

LDraw Parts Library 201802 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 201802 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201802-ec1.fc29.src.rpm

ldraw_parts-201802-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201802-ec1.fc29.noarch.rpm
ldraw_parts-models-201802-ec1.fc29.noarch.rpm

Durable Chair Mat

One of the difficulties of having a desk and an office chair where there is residential carpet is the chair-mat. Especially when it sees full-time daily use. You can spend $50 for flimsy vinyl, or $200 for high-end vinyl chair-mats. In my experience, none of them last a year; as soon as you get into the colder months and the floor cools down, I'd flop into the chair one morning and hear that tell-tale snap of cold vinyl failing. Even before the failure, the vinyl develops divots where the wheels tend to rest, and once they start to develop, gravity ensures that same location is the natural resting place for the wheels every time you sit down.

You can make your own chair-mat, and you'll find many people online who have described how they've done it, with a variety of materials. But they only show you the newly finished product; they don't show you how it's held up over the course of years. Many of them won't last, despite their creators' confident claims. Here, I distill about a decade's worth of chair mat experience.

Attempt 0

I bought a vinyl chair-mat. It died quickly.

cheap-vinyl-wear.jpg

Attempt 1

Thinking that maybe this is a case of "you get what you pay for," I bought a high-end vinyl chair-mat. When the temperature dropped and I flopped into the chair, it died with a snap. And continued to crack, and crack, and crack.

quality-vinyl-wear.jpg

Attempt 2

Let's try building something sturdier. I bought a sheet of plywood, cut it to shape, and stained the top of it. A hard, flat chair-mat that wouldn't snap when it got cold? Perfect!

Well... that lasted a while, but the rolling of the wheels across the wood grain compressed the wood unevenly, and the wood fibers began to separate.

plywood-full.jpg

That doesn't really do it justice; you need to look closer; so you can see how the wood separates with the grain.

plywood-closeup-minor.jpg

But it just kept getting worse, and the damage kept getting deeper.

plywood-closeup-depth.jpg

After a while, I was generating piles of wood splinters. I used that for about 3-1/2 years, but I put up with it falling apart for way too large a portion of that time.

Attempt 3

For my next attempt, I flipped the plywood over, and applied self-adhesive faux-wood vinyl laminate flooring (4x36" planks) directly to the plywood. I figured that would keep the plywood from coming apart, and the plywood would provide a solid underlayment for the flooring. Unfortunately, the slats of flooring immediately began sliding under the pressure of the chair. They didn't move rapidly, but as they edged away from their initial position, they exposed the gooey adhesive that was failing to hold them in place. And the slats under my feet went even faster. I had a mess under my chair in less than a week.

In fact, if you look back at the first picture of the torn-up plywood chair-mat, you can see the adhesive backing of the flooring sticking out from under it around the edges.

laminate-mess.jpg

Again, the above picture doesn't look as bad as it was. If you look closely, you can see the seams don't quite line up, but it was only in this "good" of shape because I kept pushing the slats back into place.

Attempt 4

At this point, I did some research, and found that there are two kinds of office chair caster wheels. The normal kind that comes with any office chair you buy, and a second kind made from a different plastic intended for use on hardwood floors. Hardwood floors? Hmm...

I ordered a set of those wheels and installed them on my office chair in the hopes that they'd be gentler on my next attempt.

Construction

I bought a 4'x8' sheet of 3/4" particle board to use as the base because I wanted something more rigid than the plywood I had been using before.

For the flooring, I bought faux-wood engineered flooring that snaps together at the seams.

This is the label from the flooring sample of what I used; but I'm not finding any indication that they even make this stuff any more.

flooring-product.jpg

The planks were about 5-1/2"x48" planks; that allowed me to build the chair-mat with no end-to-end seams. I glued the flooring to the 4'x8' particle board using liquid nails.

construction-glue-planks.jpg

The next day, after the adhesive had dried, I flipped the board over, cut off the excess length and trimmed the long edges.

Cutting the long edges was needed since the 48" long planks had the interlocking groove system on their ends as well; so I had to trim them to a bit less than 48" Then I rough-cut the inside corners ...

construction-cut-rough.jpg

... so that I could reach with the drill press and a hole-cutter to fillet the inner corners.

construction-fillet-corner.jpg

I also cut the outside rear corners of the mat at a 45 to give the whole thing a more interesting shape, without reducing the usable surface of the chair-mat.

construction-cut-to-shape.jpg

I bought matching quarter-round trim, and used liquid nails to glue it to the edges that would not be adjacent to the desk, with the top edge of the trim flush with the top of the flooring since I didn't want a lip. Yes, that means I can roll off the edge, but in practice that hasn't been a problem, and makes it easier to sweep stuff off of it.

construction-glue-edge.jpg construction-glue-edge-bottom.jpg

construction-finished.jpg

I also later added nylon furniture sliders to the edges of the mat that were rubbing on the desk; I should have done that to begin with.

furniture-sliders.jpg

Challenges

One of the challenges building this was the weight of this thing. I damaged a bit of the edge one of the times I flipped it over because I had trouble with the weight.

The other was that cutting through the particle board and flooring caused my circular saw blade to over-heat, leading to this awful cut.

construction-bad-cut.jpg

Fortunately I learned this on the first cut to remove the excess particle board so fixing it simply meant taking another cut and losing a quarter-inch of the over-all length.

Wear

So the real question is, "How has it held up?" From a photo taken the day it was installed, you can see that the corners were nice and clean.

corner-wear-original.jpg

Due to where this corner is, it sees a great deal of foot traffic; not just when I'm going to sit down. From this picture taken after nearly three years of daily use, you can see that the cut edges had worn noticeably, but is still very serviceable.

corner-wear-years.jpg

The other location which shows some wear was mostly due to damage sustained while I was building the chair-mat. The damage is a bit difficult to see in the original photo

edge-damage-original.jpg

but the surface of that damaged area eventually broke off.

edge-damage-years.jpg

I tried to get a picture that would clearly show the wear from the wheels, but found it surprisingly difficult... though I should not have been surprised, given that until I started working on this write-up, I had not noticed any wear at all on the main flooring. Most of the color differences you can see in the picture are due to shadows or reflections, not wear.

full-wear-years.jpg

But if you look carefully, you can see that the floor is just slightly lighter in a ring (marked in blue) centered where the chair sits most of the time. This is where the wheels most often travel; but there aren't divots that the wheels roll into and stay; it's still a solid, flat surface.

full-wear-years-highlighted.jpg

And there is one part of a seam that is showing significantly more wear than the rest of the floor (circled in red) which may need some attention. Here is a close-up taken a year-and-a-half after that showing that the wear has increased some, but not rapidly:

full-wear-years-seam.jpg

At some point, I managed to step on the quarter-round edging with all my weight one time too many, and it separated from main body of the mat. A bit of liquid nails put it back on and it has held up fine since.

Looking at it overall after over 4 years of use, it has held up extremely well:

full-wear-overall.jpg

Conclusion

I'm happy with how this chair-mat has held up over the past 4+ years; when it eventually falls apart, I expect to build another much like it. Differences I may consider include using a thinner particle board so the weight is more manageable, being more generous with the liquid nails for the edge trim, and adding the nylon sliders on day one.