Nixie Tubes

Nixie Tubes
Source: https://www.daliborfarny.com/

Nixie tubes. I love 'em.

A Nixie tube (English: /ˈnɪk.siː/ NIK-see), or cold cathode display, is an electronic device for displaying numerals or other information using glow discharge. -

https://en.wikipedia.org/wiki/Nixie_tube

Made by a number of cathodes (typically 0-9) inside the vacuum tube. Send power through the cathode you want lit, it's lit. The original light emiting indicator. Vintage looking, evocative. Since I started playing with SVG, making a nixie tube was high on the list.

Process

Step 1 - Research

Research here being code for a lot of DuckDuckGo use. Finding nixie tubes, working out the common display shapes. Which breaks down to a tube, with a curved top and a nipple. Saucey.

Step 2 - Mucking about with Curves

I like drawing with SVGs as using maths makes sense to me. Playing with graphs, x & y's eternal will-they-won't-they. Straight lines or basic shapes in SVG are easy, but every time I want to make a curve I have to re-read the curve/ arc command section of the SVG guide to see what A, C, Q, T and S all mean. My mud map:

  • C: Complex curves of two customised stretch points.
  • S: Mainly for continuing existing C or S curves
  • Q: Simple curves with a single control point, so the arc endpoints have less individual curvibits.
  • T: It's S, but for Q.
  • A: Rather than using endpoints and control points, you specify X or Y radius, a couple of flags to say how to draw, and where you end up.

When drawing a path with SVG, I like starting with an initial Absolute point (capital letter to say it's the absolute X,Y position) and then drawing with Relative points (lower letter that says the X,Y position is added to the last X,Y position). In true Steampulp fashion, I think about what I want and then start throwing numbers at the wall to adjust from. I lucked out and got good curves to start with for the round top and nipple; then reflected them to create the down on the other side.

The curves for the base were next, as it's just a curve-sided rectangle with the two curved sides being the same. Again, luck was on my maths-side to come up with the initial angles.

<g id="outline">
    <path d="
        M 15,190 
        l 0,-160 
        q 2 -10 30 -15 
        l 5 -5 
        l 0 -2 
        q 5 -10 10 0
        l 0 2
        l 5 5
        q 28 5 30 15
        l 0 160" stroke="grey"/>
</g>

Step 3 - Hexcelling.

Looking close at the nixie tube, you'll see there's a hexagonal mesh that covers the numbers. I'm ... not entirely sure why it's there. I'd guess at some faraday cage protection of the cathodes. But I'm guessing. Aesthetically I need it, so I'll have to find a hex pattern.

Searching for SVG Hex Patterns found me a bunch of stock images, but I was after the algorithm not a picture. The excellent CSS-Tricks site has a page on SVG Patterns, which includes a Hex grid. I copied it down and started playing with it, but the pattern is for a very pre-calculated size and I didn't feel like reverse engineering that. So I just built my own.

Each angle of a hex corner is 60 degrees. Sin and Cos applied to that, and a bit of tweaking, ends up with enough to build a hex shape. Repeating that results in joined hexes and diamonds, adding a half-side-size stick to the top of a hex fixed that. Et Voila, a hex grid.

<pattern id="pattern-hex" x="0" y="0" width="11" height="17" patternUnits="userSpaceOnUse" viewBox="0 0 11 17">
    <path d="
        M 0 14
        l 0 -6
        l 5.5 -2.8
        l 5.5 2.8
        l 0 6
        l -5.5 2.8
        l -5.5 -2.8
        m 5.5 -9
        l 0 -6" 
        fill="none"
        stroke="silver"
        stroke-width="1"/>
</pattern>

Step 4 - Font1 of inspiration

I'd previously used a font called Nixie One, freely available from Google Fonts2. It was thin, it was already called Nixie, so I just included that in for the numbers.

 @font-face {
    font-family: 'Nixie One';
    font-style: normal;
    font-stretch: condensed;
    src: url('../fonts/nixie-one-v8-latin-regular.eot'); /* IE9 Compat Modes */
    src: local('Nixie One'), 
         local('NixieOne-Regular'), 
         url('../fonts/nixie-one-v8-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 
         url('../fonts/nixie-one-v8-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ 
         url('../fonts/nixie-one-v8-latin-regular.woff') format('woff'), /* Modern Browsers */ 
         url('../fonts/nixie-one-v8-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ 
         url('../fonts/nixie-one-v8-latin-regular.svg#NixieOne') format('svg'); /* Legacy iOS */
}
text {
    font-weight: 100;
    font-size: 120px;
    font-family: "Nixie One";
    font-stretch: condensed;
}

It worked, but it was a bit flaky. The loading of fonts from a specific source made for a nasty depenency. While trying to work through it, I threw some standard fonts at it ... and monospace worked Very well. So I adopted that instead. Sorry, Nixie font.

text {
    font-weight: 100;
    font-size: 120px;
    font-family: monospace;
    font-stretch: condensed;
}

Step 5 - Layers of character/ Glowing up

As indicated above, when building an SVG there's no concept of z-index. What is first in the SVG is overwritten by anything that comes later. It just means you have to manage your layers like GiMP or other tool and manually shuffle them around.

To get a glow, I went back to the trusty internet and found a wealth of tools on how to add glows to SVG using filters and gaussian blurs. I honestly had NO idea that SVG had this sophisticated level of filtering before I read up on this technique. Looks like there's even more to SVG's filtering than this, it's worth a squizz.

Regardless, I added a few different layers of filtering over a character, then added a 'dead' character last to give it a thing to make glow.

<g>
    <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: orange; stroke: orange">0</text>
    <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: #c46210; stroke: #c46210">0</text>
    <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: orange; stroke: orange">0</text>
    <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: #c46210; stroke: #c46210">0</text>
    <text x="55" y="140" text-anchor="middle" style="fill: #000; stroke: orange;stroke-width:3">0</text>
</g>

My first Nixie I just changed the character in the text field to be the one I wanted. However being able to add a single Nixie SVG and make it display whatever I want from the parent HTML was appealing. Digging into earlier experiments for making Spider graphs, I added some JavaScript to the SVG so that I could change the character. At the same time, I added ALL the characters into the Nixie with On and Off states so, just like in the original Nixie, the other characters that aren't on are still there.

<g id="character-0">
    <g class="on">
        <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: orange; stroke: orange">0</text>
        <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: #c46210; stroke: #c46210">0</text>
        <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: orange; stroke: orange">0</text>
        <text x="55" y="140" text-anchor="middle" style="filter: url(#glow); fill: #c46210; stroke: #c46210">0</text>
        <text x="55" y="140" text-anchor="middle" style="fill: #000; stroke: orange;stroke-width:3">0</text>
    </g>
    <g class="off">
        <text x="55" y="140" text-anchor="middle" style="fill: #0001; stroke: none;">0</text>
    </g>
</g>
<g id="character-9">
…

So now I have a single SVG that I can include in a page.

Step 6 - The highlights

The glass tube did not look like a glass tube. It looked like an outline. Looking at the reference images, I need to make the glass darken what was behind it, and add some highlights.

The background is easy, I added a black fill to the shape I drew for the tube, but set the opacity way low so it just darkened the backdrop.

<g id="outline">
    <path d="
        M 15,190 
        l 0,-160 
        q 2 -10 30 -15 
        l 5 -5 
        l 0 -2 
        q 5 -10 10 0
        l 0 2
        l 5 5
        q 28 5 30 15
        l 0 160" stroke="grey" fill="#0005"/>
</g>

I then wanted to draw a highlight from the left. A simple vertical bar of white, offset to the x axis a smidge, followed by duplicating the existing curve of the glass. I then fiddled with turning that into a 2 dimentionsal shape and lucked out into making a nice bulge at the top to indicate a volume for the shape. Adding the previous #glow filters with some narrower tweaks, and the glass looked much more glass-like. A later suggestion for a tweak has added the last little glow on the nipple.

<g id="reflect">
    <path d="
        M 18 156
        l 0 -120 
        q 2 -10 30 -15 
        l 0 1
        q -2 10 -27 15
    " 
    style="filter: url(#glow2); fill: white; " />
    <path d="
        M 18 156
        l 0 -120 
        q 2 -10 30 -15 
        l 0 1
        q -2 10 -27 15
        l 0 120
    " 
    style=" fill: #fff7; " />
    <path d="
        M 50 10
        l 2 -2
        l 3 0
        l -2 4
        Z
        "
        style="filter: url(#glow2); fill: white; " />
    <path d="
        M 50 10
        l 2 -2
        l 3 0
        l -2 4
        Z
        "
        style="fill: #fff7;" />
</g>

Step 7 - All about the base

Until now I'd left the base as a fill="silver" but it didn't look great. I read around to find some good metal gradients for CSS/ SVG. I found one that was built by layering 3 different transparent-except-for-highlight gradients on top of silver, but my friend Dan Beeston linked me to a css gradient he'd made using cssgradient.io. This resulted in a much cleaner metal gradient that I applied to the base.

<linearGradient id="danBeeston">
    <stop offset="0%"  style="stop-color: rgba(96,96,96,1);" />
    <stop offset="4%"  style="stop-color: rgba(255,255,255,1);" />
    <stop offset="6%"  style="stop-color: rgba(255,255,255,1);" />
    <stop offset="11%" style="stop-color: rgba(215,215,215,1);" />
    <stop offset="36%" style="stop-color: rgba(75,75,75,1);" />
    <stop offset="73%" style="stop-color: rgba(0,0,0,1);" />
    <stop offset="83%" style="stop-color: rgba(61,61,61,1);" />
    <stop offset="85%" style="stop-color: rgba(73,66,63,1);" />
    <stop offset="88%" style="stop-color: rgba(80,73,69,1);" />
    <stop offset="96%" style="stop-color: rgba(14,14,14,1);" />
    <stop offset="99%" style="stop-color: rgba(154,127,82,1);" />
</linearGradient>

As a spot of luck the highlight matched with the glass highlight above. Victory!

Step 8 - Image trap

If you include the object as an image vi an img tag, you don't get what you want. Including as an img doesn't add any of the SVG elements to the shadow DOM, and it doesn't fire any CSS, JS or Font links, so you get a static dead nixie. Thematic, but not fun. Including using an object tag adds it to the page, so you can interact with it.

<object data="/blog/media/nixie.svg?digit=1" type="image/svg+xml" id="digit-one" width="50"></object>

Update - Step 9 - Order of events

I decided to try changing the black centre line of the nixie to match the bright glow of a real nixie. When I did that and had the default order of numbers, the higher numbers were faded out.

Default order

So I redid the order to match one of the original Nixies: 6 7 5 8 4 3 9 2 0 1. And that's the below. I like it.

And there it is, a SVG nixie tube that you can include in the page and use querystring parameters to set whatever number you like. Thoughts?


  1. Yeah... sorry. I feel dirty. ↩︎

  2. As with all google things, for a given value of Free. ↩︎