Monday, 25 August 2025

The TeochewThunder Logo Change

TeochewThunder's logo has changed. You heard it here first! Well, duh.

More than ten years have passed since I first started TeochewThunder. Back then, the logo looked like this.


I was going for something whacky in my favorite color, orange. Thus, the crying-face emoji "T___T" became my goto. And I used some super-basic text art creator (was it MS Word? I really can't recall) to put that cheeky bend on it.

The time has come for a slight change. I still want that "T___T", but I want the second "T" to look like a lightning bolt! Teochew "Thunder", right?


I'd been thinking about a brand renewal for a while now, but never quite got round to it. Mostly because while the first logo was a complete rush job and very casually done, it really grew on me the last decade. Especially when I saw it in browsers or on my mobile.

The Favicon in browser.

The Favicon in mobile.

The end result was that I kept putting off the task of creating a new logo, and implementing the change. Why fix it if it ain't broke, amirite?

That one final push

As it turned out, the choice was made for me. My trusty faithful Lenovo died, and with it the source file for the logo. This meant that if I ever wanted a fresh copy to resize or whatnot, I would have to work off existing exported images. Not exactly ideal.

Thus, I bit the bullet. This time, I created an SVG. This meant that as long as I had the formula for the SVG, I could recreate it from anywhere. All I had to do was save it to my GitHub account, and I was good for eternity. And also, being an SVG, it could be scaled up and down infinitely with no loss in quality.

New Favicon in browser.

New Favicon in mobile.

The rest of the month was spent replacing the logo everywhere I found it. I replaced it on GitHub, Trello, and on the signoffs of my blogposts. And of course, the Favicon. However, I'm too fond of the old logo to totally let it go. What I'm going to do is leave it as legacy, but use the new logo for all other content moving forward.

Keep Thundering On!

When I first learned how to make SVGs, it wasn't with this express purpose in mind. But I'm glad I invested that time and effort.

Stay iconic,
T___T

Thursday, 21 August 2025

Film Review: Black Mirror Series Six (Part 3/3)

This next one might just be my favorite of the entire bunch. It's called Beyond The Sea.

The Premise

Stanfield and Ross are two astronauts who live on a space station. They are able to visit their families by means of a technology that can transport their consciousness to avatars (called "Replicas") on Earth. Tragedy strikes as the family of one astronaut is murdered...

The Characters

Aaron Paul delivers a surprisingly nuanced performance as Cliff Stanfield, a taciturn and emotionally distant husband and father. My only experience with Paul on-screen is as Jesse Pinkman in Breaking Bad. This is Aaron Paul's second time in Black Mirror, having had a cameo voice-over in the episode USS Callister. Here, he has a dual role, sometimes acting as Cliff, and sometimes acting as David.

Former teen heartthrob Josh Hartnett takes on the role of the charming family man David Ross, Stanfield's colleague. And let me just say that Hartnett is severely underrated as an actor. From his early roles in 40 Days and 40 Nights and Pearl Harbor, I had him pegged as the Pretty Boy. But recently I saw him in Trap. And now this. Hartnett had me liking Ross, feeling sad for Ross, disliking Ross, hating Ross, and finally being utterly fucking terrified of Ross.

Kate Mara as Lana Stanfield, Cliff Stanfield's wife. I've only ever seen Kate Mara in House of Cards and the ill-fated Fantastic Four. At first, the role felt like one anyone could have done, but after Lisa Stanfield reveals the fact that her loyalty to her husband runs far deeper than the audience was led to believe, Kate Mara utterly sold me on her performance. Marvellous stuff.

Auden Thornton as Jessica Ross. This is really a thankless role. Thornton gets groped by Hartnett and then has to look tearful and terrified in another scene, and that's it for her.

Daniel Bell as Cliff's son Henry Stanfield. He's a meek, quiet kid with almost zero personality. The audience is led to believe that Cliff oppressed it out of him, but there are times we do see Cliff doing dad-stuff with his son, so I'm not really sure what they were going for here.

Rory Culkin has a small but memorable role as Kappa. All glowery menace and unhinged dialog.

Marama Corlett, Siân Davis and Ioachim Ciobanu as Theta, Sigma, Epsilon. I'm not sure I can tell them apart, really. They're just there as Kappa's insane sidekicks.

The Mood

It's a serene futuristic setup when in space, but when back on Earth, it's retro-style picket fences. That's because for some reason, this episode takes place in a reimagined past. This episode is long and takes a while to get to the meat of the story from the setup, so for the most part, it's quiet, somewhat sad in places, and interspersed with scenes of horrific violence.

What I liked

The beginning parts where they threw little hints that David and Cliff were... unusual. From the fans at the cinema theater to Cliff saying Grace but not actually eating with his family.

The shot of the spaceship is pretty neat, gotta say.


And also the design of their sleeping quarters.


Whatever it was I was expecting when they cut Ross open... it wasn't this. Honestly, I was expecting a metal skeleton of some kind. Not this... gel?! Mind blown. Points for originality!


That twist at the end... oof. I really thought Ross was going to murder Stanfield or something, but no, I was totally blindsided. In fact, the entire episode subverted my expectations again and again.

The characters and the dialogue are pretty well-done. It wasn't just the work of the actors that made these characters shine; it was the way they were -written-. Cliff and David weren't just good or bad guys, they were relatable, flawed men who loved sincerely and deeply. As they went back-and-forth, my sympathies shifted from David, to Cliff, then to David again. I know none of the characters actually deserved what they eventually got, but at some points they let the worst parts of themselves come through, with tragic results.

Also some of the details were pretty nice. Like when Cliff searches David's quarters and we see all the stuff his kids left for him.




What I didn't

You'd think that with these high stakes, the company would send more than the mimimum headcount out in space. It makes no kind of sense. Two people leaves very little wriggle room for accidents, mishaps and the like. This is an extended trip in space, not a buddy cop patrol beat. What's worse, the two-man thing was actually a major plot point, which drive many of the characters' decisions. Too bad it didn't make sense in the first place.

This episode went on a little long, but it's a minor quibble and one I'm inclined to forgive, all things considered.

Conclusion

Possibly the strongest episode so far, despite its flaws. That twist hit like a gut punch. The story played me like a fiddle from start to finish. And that ending was really the fucked-up finish to end all fucked-up finishes.

My Rating

9 / 10

Thoughts on Black Mirror Series Six so far

As with previous seasons, this one has been a mixed bag. Mostly positive, though. Even the one episode, Loch Henry, that I didn't like that much, was pretty good. And I didn't dislike it, just didn't think it belonged in Black Mirror. But honestly, these first three episodes are a huge improvement over Series Five.

So far, Series Six isn't Awful!
T___T

Tuesday, 19 August 2025

Film Review: Black Mirror Series Six (Part 2/3)

Now for the next episode, Loch Henry!

The Premise

This next episode is Loch Henry. It takes place in a quaint English countryside, always a win in my book. A well-publicized series of murders happened here a long time ago, and a young couple starts to make a documentary about it.

The Characters

Samuel Blenkin as Davis McArdle. I last saw him in The Continental. In here, he was thin, awkward, and just kind of meek. The entire performance was so-so, really. Except at the parts where he interacted with Monica Dolan, where the actor teared up a bit. I thought those were great.

Myha'la Herrold as Pia Koreshi. The role seemed a little bland. Not sure if that was the way it was written, or just the way Herrold played it.

Daniel Portman almost steals the show as Stuart King. Loud, brash, goofy, Stuart King is the buddy we all wish we had, the one we get up to crazy shenanigans with and owns a bar so he can get you free drinks. Also, his sarcasm is a delight to watch.

John Hannah plays Start's drunken dad Richard King. As a teenager, I first watched Hannah in Sliding Doors, and then in The Mummy trilogy. Guy's a hoot, and they hit peak perfection with this casting call. As Richard King, Hannah is equal parts cranky and morose, and anguished. He makes an entire meal out of this, but without detracting from the story too much.

Monica Dolan is mother Janet McCardle. This is Dolan's second role in the Black Mirror series, the first being a rather more forgettable outing as a Chief Inspector in the dreadfully tedious episode Smithereens. She does considerably better this time round playing an anxious and awkward mother who's really an enthusiastic accomplice to several murders.

Gregor Firth as Kenneth McCardle. A jovial lawman who turns out to be a perverted serial murderer. It was a somewhat believable turn, given we hadn't seen all that much of Kenneth McArdle so far.

Ellie White makes a couple appearances playing Kate Cezar, who runs Historik Productions and appears to be the boss of Davis and Pia. There's a little bit of an opportunistic vibe about her, which I guess we all associate with publishing houses.

Tom Crowhurst as Iain Adair. The part called for a mad-looking guy and Crowhurst delivered without being too obvious about it.

The Mood

It's a misty countryside and I could just about feel the cold air on my face and the rustic warmth of the bar. The tension goes up a few notches in the final act, but for the most part, it's a slow-burn kind of vibe. When Davis begins the narration of the case of the missing couple Simon and Dawn Challis, that's where a hint of it begins.


Later on, when a horrified Pia is watching a real sex murder on camera while the scene cuts back to Janet preparing food with a very lethal-looking knife, the accompanying music ratches up the tension like you wouldn't believe!

What I liked

The cast is small and tight - no one's wasted in their roles.

As mentioned before, the environment they shot this in was breathtaking in its natural beauty. Huge plus, if you ask me. And there's just something about Stuart's bar that charmed my socks off.


While I'm not a big fan of the twist itself, how it was implemented I have no complaints with. Pia accidentally overwriting a tape with incriminating evidence, and seeing just a hint of it at the end... great stuff! Makes me nostalgic for the days of old.



That last lingering shot of Janet's suicide note and the photos she left behind. So terrible, and so sad!

What I didn't

The premise is hardly original, and neither is the twist. (See 2003's Gothika for something similar) If someone as clueless as myself saw it coming a mile away...

This is supposed to be a Black Mirror episode but I see nothing about tech or media (unless you count VHS tapes).

Pia's death seemed kind of overkill, narrative-wise. I don't see what it adds to the story.

It occurs to me that Davis and Pia are the sixth (or more?) example of an interracial couple I've seen so far in Black Mirror. When it first appeared in Fifteen Million Merits and White Bear, I was all for it. Several episodes over multiple seasons later, it's gotten a bit gratuitous. Hang The DJ, San Junipero, White Christmas, Black Museum... the list goes on. Even the preceding Joan Is Awful! (Both Joan's relationship with Krish and the random couple whose wedding she interrupts) Normally, I'm pretty oblivious to this, so if even I noticed it... seriously, it feels like somebody is trying just a bit too hard.

I don't think Stuart would have called Davis to crow about the booming business in the bar. I mean, FFS, Davis lost both his girl and his mother in one go, and it turns out his parents were murderous psychopaths. I feel like Stuart can be insensitive, but surely he's not such a dick?

Conclusion

It's not that I didn't like this episode. I just didn't think it belongs in Black Mirror. There are episodes that don't have a tech angle such as Hated In the Nation or Smithereens, but still have a Media angle. This has neither. Running out of ideas?!

My Rating

7.5

Next

Beyond The Sea

Sunday, 17 August 2025

Film Review: Black Mirror Series Six (Part 1/3)

Series Six of Black Mirror is here, and what a ride it's going to be. Mind you, not always for the right reasons. You see, there was just something really underwhelming about this iteration of Black Mirror, even considering its predecessor, Black Mirror Series Five.


But you know what, I'm getting ahead of myself here. Let's give Black Mirror Series Six a fair shake and go through an episode-by-episode review before I sum up my general thoughts, eh?

Warning - many spoilers ahead...

You know the drill by now. Black Mirror is chock-full of shocking scenes and even more shocking language. And I'm going to spoil the ever-loving heck out of this one, so strap in, son!

We'll start with the first episode, Joan is Awful.

The Premise

Joan notices that a new series has premiered on her streaming service, Streamberry. To her horror, it's a series about her everyday life and mirrors everything up to and including the point where she's watching the series. Soon, everyone around her has a view into her private business now that it's available as public TV...

The Characters

Anne Murphy takes on the roles of Joan Tait and herself. Murphy really dials it up to eleven with the panic attack mid-way through the show.

Salma Hayek, similarly, takes on the roles of Joan Tait and herself. I believe that Salma Hayek needs no introduction, having graced the feverish dreams of teenage boys like myself in her 1996 hit From Dusk Till Dawn. Even having last seen her in a comedic role in The Hitman's Bodyguard, I was blown away by how willing Hayek was to ham it up. She looked like she was really having fun here.

Michael Cera as Beppe, the nerdy tech who explains everything to Joan, and by extension, the audience. He did well, I was so engaged.

Avi Nash as Krish. I've only seen this guy in The Walking Dead and I didn't know he could be this dramatic! Hats off!

Himesh Patek as Krish. Looking way more serious than Nash in that role!

Rob Dalney as Mac. Gave off instant douchebag fuckboy vibes. Dalney was effortlessly smarmy in the role.

Ben Barnes as Mac. I remember him as Jigsaw from Punisher. He makes a very limited appearance here and only really needs to look pretty.

Ayo Edebiri as Sandy. What we mostly see of her is at the scene where she gets canned. I thought she did a pretty good job representing the stages of grief with what little time she had. Denial ("I thought we were friends"), anger("You're a coward, Joan!"), bargaining("Please don't do this. Please. Not now!")...

Lolly Adefope as Joan's lawyer. I really liked the dialog here. Adefope delivers the entire "you're screwed" explanation with such creative flair.

Wunmi Mosaku as lawyer. Didn't I see her in Playtest? Well, the role here is basically regurgitating everything that Adefope already said as the lawyer, so it's not all that interesting.

Jared Goldtein as Eric. Dude delivers is lines. I love that he's gay but not over-the-top with it. Didn't even realize the character was gay until that scene with his boyfriend!

Jaboukie Young-White as Eric. I whooped when I saw this. I watch a lot of The Daily Show, that's why.

Kayla Lorette makes a brief appearance as the actual Joan Tait. Would have been hilarious and deeply ironic if they'd used a really big name for this role, but I guess that would have been a really expensive gag.

Leila Farzad plays Streamberry CEO Mona Javadi. She comes across as a massive asshole, which is great. Because this episode really needs something other than a faceless quantum computer to be the villain.

Danielle Vitalis as Fatima Klaas, the journalist who's interviewing Mona Javadi. She plays this role straight, looking both concerned and alarmed at the implications of what Javadi is showing her. In a sense, she's a conduit for the audience.


Luke Beattie is Brutus the security guard. This dude sure didn't look like a "Brutus". Sure, it was a bit part, but musclebound meatheads are everywhere, the show producers really could have done better.


Rich Fulcher as Gainsborough, Salma Hawek's lawyer. He's meek and befuddled, but he can't do shit, so I kind of felt for the character there as he got chewed out by Salma Hayek.

The Mood

The atmosphere is bright and the vibes are light even as disaster after disaster occurs. This episode is more of a comedy adventure than a tragedy, and it shows.

What I liked

The concept of Streamberry (looking uncannily close to Black Mirror's current platform Netflix) is deliciously on the nose. And also, the title design for this episode is so apt!


When Joan and Krish are going through Streamberry's shows for the first time, we're seeing references to other Black Mirror episodes. So cheeky!

The twist at the end gave rise to so many questions. Like, if everything that happens in the series is a mirror of what went on in "real life", did the real Joan Tait actually defecate in a Church?! Holy shit. Literally!

Now, I normally don't like a huge cast, but in this case it was absolutely justified. The big names such as Salma Hayek and Cate Blanchett (in the role and non-speaking cameo respectively) just added layers of context. Plus, it just tickled me.

What I didn't

After Joan's lawyer explains how Streamberry knows everything in real-time due to her phone eavesdropping on her, Joan still goes ahead and has sex with Mac (or attempts to) without taking the proper precautions?! Um...

While I loved having Salma Hayek in the cast, it just didn't make sense that this basically meant that the role of Joan Tait was race-swopped. Which in itself wasn't that big a deal, until I noticed that this was the only role where it happened. Consistency, people!


I was not really buying that quamputer design as this mega-processor. I'm supposed to believe that this is the machine behind those huge virtual worlds, the A.I generation and stuff?!

Conclusion

This entire episode is a goofy and sometimes gaudy spectacle. There's never any sense of high stakes - even as horrible things keep happening to our protagonist, they're played more for laughs. And that's not a criticism - it's perfect for this episode. Twists are aplenty. It's a wacky fun time for all, even without the typical Black Mirror tragic ending.

My Rating

8.5 / 10

Next

Loch Henry

Wednesday, 13 August 2025

A Tech Professional's Takeaways From Coldplaygate

Everyone's probably heard of Coldplaygate by now; certainly it seems like everyone's talking about it. The scandal involves tech company Astronomer, and its then-CEO Andrew Byron and HR Kristin Cabot. While it does qualify as a tech story in the sense that Astronomer is a DataOps tech company, I've put off talking about it up to now.

Why? Because, well, there were just other, more compelling things to talk about. I mean, the scandal essentially revolves around two high-ranking colleagues Byron and Cabot having an extramarital affair. It's basically two people at the workplace getting into trouble because they couldn't keep it in their pants. Nothing terribly new or original about that, is there?



What happened was that on the 16th of July at a Coldplay concert, frontman Chris Martin was shouting out concert-goers that the Kiss Cam picked up. And the Kiss Cam just happened to fall upon Byron and Cabot in the audience.

It would have been less awkward if the two of them had been in a chest-to-chest bro hug. No such luck; they were in full-on Titanic pose. Byron could have claimed he was giving Cabot the Heimlich, except his hands were entirely too high up, doing his best imitation of a Victoria's Secret underwire product, for that to be a feasible excuse.

The two of them scattered like Flat-earthers confronted with facts, and within twenty-four hours, the Internet identified the two of them as colleagues who were married... to other people.

All in all, a shitshow for Astronomer.

My takeaways to this entire thing aren't moral. Everyone seems to already be on that dog-pile, and there's no real value in me joining in. Also, I'd like to keep this about tech, or at least about the professional space.

Decision-making

Sure, obviously, the entire thing is unprofessional AF. And also kind of dumb.

Cheating on your spouses is one thing; doing it in a packed and very public stadium and expecting nothing to go wrong, is both stupid and reckless. Not exactly the kind of decision-making that inspires confidence in a Board of Directors.

Decisions, decisions.

I'd expect the CEO of a company, whose decisions affect the livelihoods of employees of said company, to make better decisions. Then again, I'm just a software dev, what the hell do I know about decision-making, right? Well, for one, I wouldn't make the decision to put myself in a position where I could be caught live on camera using my hands to keep my sidechick's mammary glands warm.

The faked apology

Soon after the incident, there was an apology posted by a troll account, pictured below. It appeared to be a post from Andy Byron addressing the events of Coldplaygate.

This fooled many people.

This was debunked fairly quickly, but apparently a lot of people were convinced it was real, and it spread like wildfire. Andy Byron was being roundly mocked for being both tone-deaf and an idiot. Unfairly, in this case.

But here's the question: why did it seem so real?

The reason, dear readers, is disheartening. Too many people in positions of authority, when called out for behaving badly, post insincere-sounding apologies like this one. Usually along the lines of "this is not who I want to be" and "I am a work in progress", and even the shade thrown at Coldplay at the end did not appear out of character simply because it happens so often. That level of entitlement is all too real, even if the post wasn't.

The simulation was, if anything, too on-the-nose. There was no A.I and deepfake involved in this deception; the troll account wasn't even trying that hard. This is deeply concerning.

LinkedIn Profiles

On Kirstin Cabot's now-inactive LinkedIn account, she described herself as "a passionate people leader known for building award-winning cultures from the ground up for fast-growing startups and multinational corporations. An influential leader and fearless change-agent, I lead by example and win trust with employees of all levels, from CEOs to managers to assistants."

Just reading that made me throw up a little in my mouth. If you want your LinkedIn profile to sound as cringe as possible, you could do worse than take notes from this one.

Word salad.

Can someone say "word salad"? What is the term "fearless change-agent" even supposed to mean to anyone? What's even more disturbing is, this is supposed to be a HR professional. Is this the kind of garbage that impresses HR? Or is it just some kind of SEO for A.I-powered recruitment? Either way, if this is the new normal for both job-seekers and hirers, we are so screwed.

Much of the sniggering has been about how someone with such a self-aggrandizing LinkedIn profile could turn out this way, but honestly, I've never held such profiles in high regard. If you're someone that would be impressed by fancy words on a LinkedIn profile that a thesaurus could vomit out, that's on you.

Conclusion

I wouldn't be too hard on Andy Byron. Not everyone can handle being in a position of power. Tends to go to ones head, you know? Both of them, in some cases. Heh heh.

Also, Kristin Cabot. Sure, call her a skank, homewrecker, whatever. But her being HR aside, what's she really done that's so different from every other woman who ever cosied up to the Boss?


Looks like they got (cold)played,
T___T

Friday, 8 August 2025

The Curious Case of the Oddly Fragile Software Engineer

Earlier in the week, I happened to come across this article on Substack. It was titled The Manager I hated and the lesson he taught me by one Stephane Moreau. I was immediately intrigued because I am a software developer and I've worked for people I hate.

Well, actually, hate is a strong word. It's hyperbolic. Do I like them as people? Not at all. Do I wish physical harm or financial ruin on them? Not really either, no. In all fairness, if they were on fire, I might hesitate only a full five seconds before rushing over to help them like a decent human being by stamping on them as hard as humanly possible - to put the fire out, you understand.

When someone's on
fire, stamp on them.

Most of all, I'm a proponent of the idea that you can learn things even from people you don't like. Sometimes especially from people you don't like. Like, how many of such people have I learned from, how not to be a jackass? Countless!

But I digress...

The intention today was to discuss Stephane Moreau's thoughts on the manager he hated. His larger point I have no issue with - what I found really interesting was his description of what caused him to hate that Manager.

From what I saw, it started with a code review in which the Manager had this to say.
Over-engineered. Too many moving parts. Refactor.


This seemed pretty straightforward to me. A statement, an explanation, and an instruction, all in three short sentences. Moreau, however, didn't think so. This is what he had to say...
That was it. No "nice work". No "good attempt". Just a hard stop.

I sat there, fuming. I thought, "Does this guy enjoy tearing people down?"


Getting shot down.

Gee, I dunno. This seemed a bit much. I thought the Manager's comments were clear enough. What had Moreau been expecting, an essay? I didn't understand the part about "tearing people down" either. In fact, I feel like if the Manager had prefaced it with "nice work" or "good attempt", it would have felt patronizing. Which is perhaps worse than being curt. I don't need to be treated like I'm special. I do need to be treated like a professional, and that cannot happen if the Manager is feeling the need to (metaphorically) pat me on the head and throw me a bone.

This is why I can't relate

There was another line which Moreau took exception to, and at times described as "brutal".
This is fragile. What happens under load? What's the rollback plan?


And this.
You're thinking like a coder, not an engineer. Build things that survive failure.


I have received feedback like this before from my then-CTO. I was told that I approached things like a coder, and he expected more. I had no problem with this feedback, and would not have described it as "brutal". 

What baffles me is that the only way the Manager could be seen as "tearing people down" was if Moreau had seen himself as being above that kind of criticism. And in contrast, I've never seen myself as anything but mediocre. Frankly, from reading Moreau's stuff, my perception of him is that he's a humble and chill kind of guy, so perhaps he was merely relating a story from when he was young and dumb.

Like a kid with crayons.

Know what's brutal? Having your work torn to shreds and being told you write code like a toddler who just got crayons. Outright questioning what you contribute to the company. That's what I got from the above-mentioned CTO. Honestly, if Moreau had received that kind of feedback, I wonder how he would have wilted. The entire article just made Moreau look fragile, like some kind of snowflake.

Perhaps the culture in the Southeast Asia is just a lot different from the UK. Perhaps the general problem is that we're just not such a warm, nurturing environment. Here in sunny Singapore, I have the memory of being conscripted into the Singapore Armed Forces at the tender age of 19, and being yelled at by platoon sergeants on my first day... and my first thought was: Bitch please. You're think you're scary? I have a Cantonese mom.

In summary

Moreau made a whole slew of valid points in his article. I don't actually disagree with any of it. What I do take issue with, is the examples he used. As far as I'm concerned, those weren't put-downs from his then-Manager. If he wants put-downs, I've got some really savage ones.


Nice work, TeochewThunder. Good attempt!
T___T

Monday, 4 August 2025

Artificial Intelligence Experts join Meta... but it's not about the money? Really?

It was with some amusement that I spotted this article in recent times. In it, Meta head honcho Mark Zuckerberg is reported to have debunked the suggestion that A.I experts aren't joining Meta for money.

For context, Zuckerberg has been luring top A.I experts from Apple, Google and OpenAI. Interesting news, though not exactly noteworthy now, is it? Big Tech firms poaching from other Big Tech firms; nothing to see here, move along.

Meta catching those flies.

What was noteworthy was Zuckerberg's reaction to the suggestion that these new hires are joining for more than just the monstrous paycheck. He said these people were joining Meta for the opportunity to build superintelligent A.I systems without all the red tape and shit. Obviously, I'm just paraphrasing here, but you get the gist!

Wow, Zuck. Just wow. 

Just to be fair, while that statement elicited incredulous laughter, there have been reports that some companies in the A.I race have been less than enthused about A.I research for the sake of A.I research, seeing it as more of an avenue for profit. The thinking of business people, basically. 

And of course, being able to play with fancy new toys with almost unlimited resources is always nice. I imagine the "no red tape" thing was icing on top of a substantial cake.

But to say it's not about the money? That's a load of Facebook-shaped cap and we know it.

Facebook-shaped cap.

While I will concede that money probably isn't the only motivation, the fact remains that it's a pretty sizeable one.

Everyone, in some shape or form, is doing it for the money. Anyone who isn't, is either already unimaginably rich or just nuts. Meta's recent acquisition of Apple's top A.I engineer is costing them USD 200 million a year. That's not chump change, chum. (Say that three times fast, I dare you!) Apple declined to meet that price. Yes, Apple

What about the claim of building a superintelligence? Well, that requires context. For intelligence, what are we comparing against? The idiots currently raging on Social Media about Sydney Sweeney's jeans? The ones busy politicizing the death of Hulk Hogan? That's not a terribly high bar, really.

Final thoughts

All this is not to say that these AI experts shouldn't take the money. Au contraire, they absolutely should. A.I could be the thing of the future, that much is true. But it's hard to tell because that's what they all once said about NFTs and the Metaverse. Meta was even named after the latter!

Therefore, these A.I experts should make hay while people are still willing to pay them that amount of money, on the off-chance that this doesn't last. As history has proven, tech can be a fickle mistress.

"It's not about the money, money, money"... really?!
T___T

Thursday, 31 July 2025

Do techies lean Liberal or Conservative? (Part 2/2)

Welcome back!

As promised, we will be diving into the three points I outlined previously, and we'll examine how these positions could actually be Conservative ones rather than Liberal.

How Software Developers are Conservative

Identity does not matter. This principle applies both ways. The same way we wouldn't discriminate on basis of race or gender or what-have-you, we also would not use it as a criteria of preference. You may claim this is contradictory, and you'd be wrong. This is entirely consistent with our worldview. Only the tech matters.

This isn't important, or
even relevant.

Now, sure, I know Silicon Valley has DEI programs in place. I promise you, those are most assuredly implemented by HR, or Management who want to appease some Liberal demographic. The average techie, however, simply does not give a flying fuck.

You ask any techie, and their first question is more likely to be "what's your tech stack?" rather than "what are your pronouns?"

Innovation versus tradition. Now, earlier when I said that techies prefer innovation over tradition, that was true. It may also have given you the impression that techies are risk-taking swashbucklers, which, to be honest, makes us sound more awesome than we probably deserve.

The truth is, techies are boring and consistent to a fault. We like things to be neat and make sense. If we did things a certain way, in the past, we are likely to do so again unless there are good reasons against it. We obey coding styles and naming conventions and follow software patterns because doing so makes it easy to troubleshoot when things go wrong.

Things are done a certain
way, for good reason.

One of our greatest frustrations is when people do things willy-nilly and just "wing it" because this is messy and asking for trouble down the road. We don't do things one way because we suddenly feel like doing so - we do them a certain way because it's worked for us in the past, but we are open to changing it if there's good reason to do so. Again, this is consistent with the previous, seemingly Liberal, position.

The collective versus the individual. This next point is more true now than it was when I first started out.

Developers accomplish things in teams. Software development is a team sport. There is really no way around it in this day and age. Tech has evolved so much that there is zero chance of one person knowing everything - now this knowledge requires a team.

Functioning as a unit.

Remember I said that developers are a diverse lot? It is precisely this diversity that lends itself to building effective multi-disciplinary teams. And in this way, it is often the collective that trumps the individual.

Some parting thoughts on the Culture Wars

Even similar positions can take on a Liberal or Conservative lens depending on how one views it. This shows me that both sides actually have a lot in common, Culture Wars be damned. And this perspective today is perhaps more relevant than ever now that the Culture Wars have arrived at what I can only describe as a very odd place.

Americans on Social Media now squabble over the dumbest shit imaginable. Recently, I had the pleasure of watching Superman, and went on Facebook to check out some reviews and see how other moviegoers found the film. Imagine my surprise when I found people embroiled in intense arguments over whether Superman was an illegal immigrant. I suppose technically, he is, but don't these nerds have better things to talk about?

Apparently not! I soon came to the realization that this was bigger than I initially thought. It had stemmed from the director and producer, James Gunn, making a remark about how Superman was an immigrant. The Liberals began drawing parallels to recent treatment of immigrants in the USA. And then people were in each other's faces about how they didn't understand Superman and weren't real Superman fans if they preferred/didn't prefer this Superman.

I mean, attempting to gatekeep who is and isn't a fan of a fictional superhero character? Tell me you're a loser without telling me you're a loser.

I'd initially thought this argument was basically a bunch of loser nerds obsessing over obscure details. It turned out to be way more ridiculous than that - it was a mob of wankers on the internet all trying desperately to justify feeling morally superior to the other side. Conservatives such as Ben Shapiro started trashing Superman as "woke garbage" and bitching in bizarre fashion about how the character wasn't American enough. One Susan Sarandon went onto Instagram to make it all about Israel and Palestine.


True, being good and kind does not require athleticism or talent. Any idiot is capable of kindness, and I would have it no other way. On the other hand, it just feels like a whole bunch of untalented schmucks just decided to overcompensate for their lack of talent and real-world achievement by blowing their trumpets about "kindness and empathy" just so they could feel accomplished, or something.

And as for people like Shapiro and Sarandon... massive cringe, man. People need to understand when they've taken things far enough and it's getting absurd. It's come to a point where people can't sit down and watch a decent superhero movie without trying to score political points. 

Dysfunction, thy name is America.


Your cultured programmer,
T___T

Monday, 28 July 2025

Do techies lean Liberal or Conservative? (Part 1/2)

Since the day I became aware of the Culture Wars over in the good old US of A, there's been a nagging question in the back of my mind. What side do techies really stand on? I'd like to think that we aren't a slave to any ideology - especially coming from Singapore, we're a pragmatic people who believe in whatever works in the most efficient way possible.

Silicon Valley does appear largely Liberal, or at least, that's what they would have us think. Jeff Atwood of Coding Horror, founder of Stack Overflow, actually jumped onto the anti-Trump bandwagon. However, after the recent electoral victory by the Republicans on the 5th of November last year, Big Tech has quite handily changed their tune. As I've often suspected, that's not the tech part speaking; that's the business part. That the appearance of Liberal domination in Silicon Valley was a veneer, and ran no deeper than that.

Nothing deeper than that!

And thus the question was begged. The answer, of course, that software developers, like many people, identify with both. They have some positions that are Liberal, and some that are Conservative.

The funny thing is that I identified three positions that could be considered both Liberal or Conservative, depending on one's perspective.

How Software Developers are Liberal

Identity does not matter. Software development is a field where logic reigns supreme. At some levels, it does not even require a particularly high I.Q, just the ability to do basic math and thick logically. Gender, race and sexual orientation don't determine an individual's ability to do math, and as such, are irrelevant when it comes to the ability to code, test and deploy software. A software developer is not going to automatically think that another software developer is competent based on identity.

Software
development isn't
just mens' work.

In fact, one of the most baffling (and frankly insulting) things I have heard as a developer is being told that I should be better at the job because I'm a man. What, and my years of hard work count for nothing? I'm naturally supposed to be better at it because God made boys engineers by default? Well, that's not what this tech thinks, and any male tech who tells himself that kind of rubbish, does himself (or anyone) no favors.

Innovation versus tradition. Don't get me wrong, we do have our traditions. But technology itself is a result of innovation and experimentation; daring to try new things. Thus, you will never hear a software developer saying that we should do something this way just because that's how we've always done it. That kind of argument holds no water for us. It runs counter to everything that drives a techie.

Tradition has its
charm.

We may respect tradition, but we are not slaves to it. There are no sacred cows. Tradition has its place, but tradition should also know its place.

We have tech innovations today precisely because we dared to go against tradition. We dared to challenge the pre-existing ideas of what was possible, or acceptable. What separates us from the herd is the willingness to ruthlessly drop tried and tested methods in favor of demonstrably better methods.

The collective versus the individual. Skillset-wise, you will never see a more diverse group. That's because in the tech landscape where there are very frequent changes and new things to learn, people end up learning across different (but often related) tech disciplines or going deeper into existing ones.

Tech skillsets come in all
shapes, sizes and colors.

There are no unifying standards as to what makes a techie, though there's been no shortage of would-be gatekeepers trying to keep things neatly classified. It's a lost cause.

Take any two developers, even from a broad collection of, say, back-end developers, and you may end up with one mostly trained in Java and one trained in Python. Take your two developers from a less broad group of Python developers, and you might get one who's more of a web scraper and one who's more of a data analyst.

Yes, tech itself is a huge domain, and evolving as I write this. Consequently, its practitioners are similarly varied.

Next

How we're Conservative.

Wednesday, 23 July 2025

JavaScript now has negative indexing... sort of

Searching arrays in JavaScript (or any language, really) can be a tricky proposition. One of my favorite ways to search for a value within an array in JavaScript, is the indexOf() method.

With this method, I just need to invoke it while passing in the string to search for, as an argument.
var arr = ["This", "is", "a", "test", "array"];
var index = arr.indexOf("test"); // 3

But what if I wanted it the other way round? What if I wanted to find out what value was the, say, third element in an array? Well, simple enough.
var arr = ["This", "is", "a", "test", "array"];
var val = arr[2]; // "a"

Now, what if I wanted the second last element in the array?

In Ruby, one could do this. This is known as negative indexing.
arr = Array["This", "is", "a", "test", "array"]
val = arr[-2] // "test"

In JavaScript, this doesn't fly. Get the length of the array, less 2, then use it as the index.
var arr = ["This", "is", "a", "test", "array"];
var val = arr[arr.length - 2]; // "test"

There is a way to use negative indexing in JavaScript, though. Use the slice() method.
var arr = ["This", "is", "a", "test", "array"];
var val = arr[-2, -2]; // ["test"]

The end result is an array, though. So there's one more step to take before you can access the value.
var arr = ["This", "is", "a", "test", "array"];
var val = arr[-2, -2]; // ["test"]
val = val[0]; // "test"


So, those are the things you have to do, in order to get the value of an element n times from the end... or do you? Now with the at() method, you literally just need to do this.
var arr = ["This", "is", "a", "test", "array"];
var val = arr.at(-2); // "test"

What is this sorcery?!

The at() method was introduced as recently as 2023. With it, a programmer can do in JavaScript what one can do in Python and Ruby - use negative indexes. Is that really so important considering that functionally, we already had all we needed in the slice() method?

slice(), slice(), baby.

Well, the slice() method complicates things. Sure, it's a handy method that can be used for big or small cases, but for the case we're talking about, it's complete overkill. Using the at() method makes code a lot more readable, and the importance of that cannot be understated.

Conclusion

It's always fun to see how programming languages evolve. Would have been nice for me to discover the at() method sooner than years after it emerged, but this only goes to underscore the fact that things change so fast in this industry and there's often something new to learn.

["Thanks", "for", "reading", "and", "see", "you", "again!"],
T___T

Saturday, 19 July 2025

Five Reasons to learn Web Development in 2025

Recent events such as the rise of generative A.I, have made tech work a little less attractive than it used to be. Web development, in particular, has suffered. That's probaby because a large chunk of web development is automatable, and even before A.I came on the scene, there had been numerous tools such as Content Management Systems and Low-code development platforms.

Thus, web development being automated by A.I was par for the course.

Robots writing websites.

Still, not all is lost. While web development might have lost much of its luster, there are still good, strong reasons to pick it up in ones tech career. Unlike the tech reporters and HR executives who write listicles like these, I have actually been a web developer before. I speak from experience, my dudes. And following are some of the most compelling reasons I had, in no particular order of importance, for going down this path.

1. No complicated installation

Ever tried to learn a language like PHP or Java? Every single one of these languages requires you to set up some kind of compiler or interpreter environment. PHP requires an Apache server. Java needs the Java Runtime Environment. You can write all the code you want, but until the code gets compiled or interpreted by the environment that you have to install and set up, you're not getting even a Hello World program done.

All you need is a browser.

HTML, CSS and JavaScript, however, do not. All of them already run in any major browser - Firefox, Chrome, and so on. In effect, the environment is right there for you.

This is not to say that you will never need to do any complicated installation. But for the basic building blocks - again, HTML, CSS and JavaScript - of web development, you don't. You will need to do that when you want to pick up a server-side language and maybe databases and definitely for the NodeJS style of development. But for basic stuff? Even the slightly more advanced stuff? Nope, not even a little bit. That is a lot more than you could ever say about other programming languages or platforms.

2. Good skill spread

When you learn web development, you learn HTML, CSS and JavaScript as a base starting point. That's already a good spread right there.

HTML and CSS are where you learn front-end and possibly even design. When you learn JavaScript, in addition to all the things you pick up when learning a programming language such as operators, arrays, branching and iterative logic, you also learn asynchronous operations and DOM manipulation.

A good spread of tools.

That's not to say that other tech disciplines don't have their own unique perks. But where it comes to the skill spread, web development wins. I don't think anything else even comes close.

Once you get past the basic toolset of HTML, CSS and JavaScript, back-end programming and databases will come into play. It's never just web development. Even if you are averse to the thought of being a humble web developer for the rest of your career, there are far worse places to start.

3. Resources

Now, when I say "resources", I don't just mean documentation, references and learning materials, though there's plenty of that, yes. But web development is not special in that regard because any other tech discipline boasts plenty of learning resources and a community dedicated to helping each other learn.

A good learning
community.

Though, in this case, web development has something extra.

You see, every humble HTML page on the internet can have its source viewed and played with in the browser, reverse engineered, and so on. Every URL on the internet is potentially a resource for learning, much like how I learned to cobble together JavaScript widgets decades ago.

In contrast, it's not possible to just take any desktop application and reverse-engineer the code, because the code has already been compiled and is no longer human-readable.

4. Ready use case

Often, when learning a programming language, it's helpful to be able to use newly-acquired skills to build something, so as to really hammer home the muscle memory. Something both relevant and useful, preferably. Not that Hello World programs don't have their place, but if one wishes to level up, better use cases are the order of the day.

And with web development, those use cases are almost too easy to find. Web development creates web pages, at the minimum. And after that, at varying levels of complexity, web applications. One does not have to stretch too far to find something worth building... and because it already exists, you know that it is both worth building and possible to build.

Applying what you learn.

My larger point is that what you learn can readily be applied. Not just in creating and editing websites, but in general software development. This also means that your chances of landing a job with that skillset cannot be understated. In this day and age, web developers are perhaps not nearly as in demand as they were a decade ago, or paid nearly as well, but the skillset goes beyond just web development.

For example, a lot of existing software already leverage things like REST API endpoints. These are basically URLs, which are pretty much the backbone of the web. REST is an almost inescapable part of the whole web development deal. Ergo, if you deal in web development, at some point you are going to be dealing with REST endpoints, which overlaps a large part of software development regardless of discipline.

Or even mobile development. In case you weren't aware, a large chunk of mobile tech is basically HTML, CSS and JavaScript.

I could go on... but do I really need to?

5. No gatekeeping

In the legal profession, there's the Bar Exam. In the medical profession, there's the Medical Regulatory Authority. In tech? Other than job interviews which exist at almost every industry, there's almost no gatekeeping in tech. Even the requirement for Degrees of Diplomas is not a really hard one.

When I say "no gatekeeping", I don't mean that nobody tries to gatekeep. The fact is that many people try to gatekeep, but it just doesn't work because to gatekeep, one needs a unified set of standards. It's almost impossible to establish said standards in a landscape as varied as tech, whose goalposts shift constantly.

The gatekeeper.

And while this inability to gatekeep exists in many areas of tech, none moreso than web development. HTML, CSS and JavaScript are fairly stable at this point, but these are just the base technologies. Their offshoots - frameworks, libraries and the like - keep springing up like mushrooms. And when you consider databases and backend programming languages, the possibilities multiply even more.

All in all, one could come in anytime in web development, and still be relatively fresh and relevant. No one can stop you from making and publishing web pages and applications, not in the same way they can stop you from practising law. You don't need a license to write code, so nobody can revoke it.

Some clarifications

The reasons stated here are in relation to those for choosing other tech fields. Why, for instance, web development when you could go for Data Analytics or cybersecurity? Reasons specific to web development.

I was inspired to compile this list because there are a lot of vague, generic and - to be brutally honest - trite lists out there on the web that extol the virtues of web development. Hopefully this is a better list.

<html>Bye for now,</html>
T___T

Saturday, 12 July 2025

Web Tutorial: The Cigarette Break Browser-based Screensaver

Following the one-year anniversary of having quit smoking, now that I no longer take smoke breaks, I do the next best thing - I make my browser take smoke breaks. Heh heh. For real, though. This occasion's web tutorial is centered around the idea of browser idle time. When the browser is left alone for a suitable amount of time, a screensaver comes up! And in this case, I want it to feature a smoking cigarette.

And the more time passes, the shorter I want the cigarette to get. Oh, and there needs to be animation.

Can I squeeze all of that into a single-part web tutorial? Let's find out!

Some HTML as usual. There's some Lorem Ipsum text, and a div with the id overlay. In the CSS, we want to set the outline for all divs to red.
<!DOCTYPE html>
  <html>
  <head>
    <title>Screensaver</title>
    <style>
      div { outline: 1px solid red; }
    </style>
    <script>
    </script>
  </head>

  <body>
    <h1>Some sample text. Leave this screen alone for 5 seconds to see the popup!</h1>    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et justo sit amet libero interdum bibendum at nec dui. Mauris lacinia sapien nec blandit dapibus. Nunc suscipit in nunc in finibus. Praesent mi arcu, convallis auctor auctor luctus, gravida eget enim. Nunc quis finibus nisl, semper hendrerit nisl. Curabitur faucibus, velit varius efficitur suscipit, nibh ipsum bibendum turpis, placerat elementum nulla lorem eget diam. Phasellus lobortis aliquet leo, non aliquet mauris volutpat vel. Aliquam facilisis dui id sapien dignissim vulputate. Nullam cursus convallis sem vel maximus. Sed ac sollicitudin justo, at vehicula ligula. Praesent sit amet tellus massa. Nam nec varius ipsum.</p>
    <p>Cras varius, nisl vitae lobortis sodales, purus ligula dictum eros, volutpat finibus neque sem et ligula. Vivamus id odio varius, blandit elit sit amet, scelerisque enim. Sed luctus molestie leo, suscipit ultricies nisl elementum id. Donec lacus erat, laoreet vel viverra vel, aliquam vitae elit. Vestibulum venenatis congue lacus a facilisis. Nulla condimentum, metus volutpat rhoncus maximus, purus mauris imperdiet dolor, at bibendum lacus justo nec risus. Praesent scelerisque libero magna, at lobortis justo convallis vel. Suspendisse cursus, odio ultricies auctor laoreet, ligula leo vulputate diam, et efficitur mauris nisl et urna. Quisque sit amet rutrum magna. Aenean at vestibulum urna. Nam ornare justo a tortor molestie auctor. Quisque at malesuada mi, volutpat feugiat sem.</p>
    <p>Vestibulum luctus tempor ligula. Nulla id tortor ut est rutrum viverra. Etiam nec sapien id massa egestas dapibus at ut ipsum. Nunc sed tortor euismod, aliquet arcu et, commodo justo. Proin pretium vel neque sed maximus. In vitae vestibulum quam. Integer quis ex in ligula varius tempus. Donec diam arcu, faucibus eu aliquet nec, dapibus at sem. Sed convallis urna neque, tristique condimentum mauris condimentum vel. Praesent eu interdum quam, at ullamcorper augue. Mauris euismod odio libero, vel pharetra lorem egestas et. Nam laoreet ultricies venenatis. Integer ante risus, commodo nec eros ac, convallis tempus magna. Maecenas dictum lacus magna.</p>
    <p>Proin eu iaculis felis, sed lobortis lectus. Pellentesque malesuada diam eu porttitor aliquam. Fusce posuere dapibus odio vitae suscipit. Mauris consectetur, tortor et pulvinar auctor, ante eros ornare nunc, non fringilla neque quam sed erat. In velit turpis, ultricies ut egestas in, porttitor eget erat. Sed et risus molestie, maximus mauris eu, accumsan sem. Sed pellentesque feugiat elit. Integer nisl nulla, condimentum eu purus id, vestibulum commodo ligula. Phasellus consectetur, justo in mollis egestas, nisl felis laoreet ipsum, ac feugiat nunc ante sit amet risus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla in enim lacus. Proin nulla dui, dictum at porttitor et, consectetur ac augue. Aliquam fringilla ex nec diam efficitur, vel vehicula mi molestie. Phasellus pellentesque in sem vitae porta. Nulla ut ultricies enim. Duis eu mauris sit amet lectus mattis efficitur molestie non magna.</p>

    <div id="overlay">
    </div>  </body>
</html>


Now, the modal popup is going to be visible by default - for now. For that we have the styling for overlay. position will be absolute, and we will set height and width properties to cover the entire screen with a translucent black background. left and top properties will be at 0px so as to begin on the top left corner of the screen. And of course, display is set to block to be visible by default.
<style>
  div { outline: 0px solid red; }

  #overlay
  {
    width: 100%;
 
    height: 100%;
 
    position: absolute;
 
    left: 0px;
    top: 0px;
    background-color: rgba(0, 0, 0, 0.5);
    display: block; 
 }

</style>


The first step of many steps!


Let's follow up by adding a div, styled with the CSS class content, in there.
<div id="overlay">
  <div class="content">

  </div>

</div>


We'll style it like this - a square with a black background and rounded corners set in the middle of overlay.
<style>
  div { outline: 0px solid red; }

  #overlay
  {
    width: 100%;    height: 100%;    position: absolute;    left: 0px;    top: 0px;    background-color: rgba(0, 0, 0, 0.5);    display: block;  }

  .content
  {
    width: 500px;
    height: 500px;
    margin: 5% auto 0 auto;
    background-color: rgba(0, 0, 0, 1);
    border-radius: 30px;
  }
</style>


Yep, here's that black square. Impossible to miss.


We introduce a new div inside that one, and style it using the CSS class cigarette.
<div id="overlay">
  <div class="content">
    <div class="cigarette">
    </div>
  </div>
</div>


This is how we style cigarette. It is a long vertical rectangle set in the middle of its parent, content. Think of it as a holder for all the divs that will make up the components of the cigarette.
.content
{
  width: 500px;
  height: 500px;
  margin: 5% auto 0 auto;
  background-color: rgba(0, 0, 0, 1);
  border-radius: 30px;
}

.cigarette
{
  width: 50px;
  height: 400px;
  margin: 10% auto 0 auto;
}


All in position, so far!



Now we'll do the individual parts of the cigarette. We have two divs - the first styled using body and the second styled using butt.
<div class="cigarette">
  <div class="body">

  </div>

  <div class="butt">
  
  </div>

</div>


body takes up full width but only 300 out of the 400 pixels on offer. There is explicitly no background.
.cigarette
{
  width: 50px;
  height: 400px;
  margin: 10% auto 0 auto;
}

.body
{
  width: 100%;
  height: 300px;
  background-color: none;
}


butt, similarly, takes up fill width and has only 100 pixels height. We have as its background a linear gradient, going from brown, yellow, then brown again.
.cigarette
{
  width: 50px;
  height: 400px;
  margin: 10% auto 0 auto;
}

.butt
{
  width: 100%;
  height: 100px;
  background-color: rgba(255, 170, 0, 1);
  background: linear-gradient(90deg,rgba(255, 170, 0, 1) 0%, rgba(255, 255, 170, 1) 50%, rgba(255, 170, 0, 1) 100%);
}


.body
{
  width: 100%;
  height: 300px;
  background-color: none;
}


This is what it looks like now. We'll be working on the empty-looking div next.


In body, we nest two more divs. Instead of classes, they will have ids because this will make them easier to manipulate via JavaScript later. The ids are empty (because that div represents "empty" space) and burnable (because it's the part of the cigarette that gets "burned").
<div class="body">
  <div id="empty">

  </div>

  <div id="burnable">

  </div>

</div>


body has 300 pixels in height, so empty takes up 50 and burnable takes up 250. burnable has a linear background that goes from light grey, white, then light grey again.
.body
{
  width: 100%;
  height: 300px;
  background-color: none;
}

#empty
{
  width: 100%;
  height: 50px;
}

#burnable
{
  width: 100%;
  height: 250px;
  background-color: rgba(255, 255, 255, 1);
  background: linear-gradient(90deg, rgba(230, 230, 230, 1) 0%, rgba(255, 255, 255, 1) 50%, rgba(230, 230, 230, 1) 100%);
}


So now we have an unlit cigarette.


In burnable, we have a div styled using the tip CSS class.
<div id="burnable">
  <div class="tip">

  </div>

</div>


tip has a height of 5 pixels and takes up full width; that's all there is to it.
#burnable
{
  width: 100%;
  height: 250px;
  background-color: rgba(255, 255, 255, 1);
  background: linear-gradient(90deg, rgba(230, 230, 230, 1) 0%, rgba(255, 255, 255, 1) 50%, rgba(230, 230, 230, 1) 100%);
}

.tip
{
  width: 100%;
  height: 5px;
}


In that div, let's add three divs, each styled using the ember CSS class.
<div id="burnable">
  <div class="tip">
    <div class="ember"></div>
    <div class="ember"></div>
    <div class="ember"></div>  </div>
</div>


ember is floated left and has an orange background.
.tip
{
  width: 100%;
  height: 5px;
}

.ember
{
  float: left;
  background-color: rgba(250, 150, 0, 1);
}


However, height and width vary according to their order. There are three divs in there, styled using ember, and we use the nth-of-type pseudoselector, passing in either "odd" or "even" and then adjusting the width and height accordingly. The middle (or second) "ember" is supposed to be the largest one.
.ember
{
  float: left;
  background-color: rgba(250, 150, 0, 1);
}

.ember:nth-of-type(odd)
{
  width:15px;
  height:3px;
}

.ember:nth-of-type(even)
{
  width:20px;
  height:5px;
}


Just for fun, let's add a bit of animation. This is totally superfluous. The animation name is emberglow and we want it to last for 2 seconds, run forever, and alternate smoothly between states. You'll see that for emberglow, I basically have background go from orange to red.
.ember
{
  float: left;
  background-color: rgba(250, 150, 0, 1);
  animation-name: emberglow;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-direction: alternate;

}

.ember:nth-of-type(odd)
{
  width:15px;
  height:3px;
}

.ember:nth-of-type(even)
{
  width:20px;
  height:5px;
}

@keyframes emberglow
{
  from { background-color: rgba(250, 150, 0, 1); }
  to { background-color: rgba(255, 0, 0, 1); }
}


There you go, a glowing tip! I feel like there's a filthy joke I could insert here, but let's move on...


In empty, we insert divs. Several divs. But let's just start with three. Style them using the CSS class smoke.
<div id="empty">
  <div class="smoke"></div>
  <div class="smoke"></div>
  <div class="smoke"></div>

</div>


Give each of them a random height, weight, margin-top and margin-left property. Do bear in mind that the effective width of empty is 50 pixels due to its parents, so the sum of margin-left and half of width shouldn't exceed 50, otherwise we'll have an overflow problem. Similarly, if we subtract half of width from margin-left, it should not be less than 0. width and height should be the same. You can have negative values for margin-top if you want the divs to overlap.
<div id="empty">
  <div class="smoke" style="width:15px;height:15px;margin-top:5px;margin-left:25px;"></div>
  <div class="smoke" style="width:20px;height:20px;margin-top:-2px;margin-left:10px;"></div>
  <div class="smoke" style="width:18px;height:18px;margin-top:0px;margin-left:5px;"></div>
</div>


smoke has a translucent white background and a nice fuzzy grey outline by way of the box-shadow property.
#empty
{
  width: 100%;
  height: 50px;
  background-color: rgba(0, 0, 0, 1);
}

.smoke
{
  background-color: rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  box-shadow: 0 0 15px rgba(255, 255, 255, 0.5);
}

#burnable
{
  width: 100%;
  height: 250px;
  background-color: rgba(255, 255, 255, 1);
  background: linear-gradient(90deg, rgba(230, 230, 230, 1) 0%, rgba(255, 255, 255, 1) 50%, rgba(230, 230, 230, 1) 100%);
}


And that's how the first three divs would look like.


Add several more! Make sure width, height, margin-top and margin-left properties vary.
<div id="empty">
  <div class="smoke" style="width:15px;height:15px;margin-top:5px;margin-left:25px;"></div>
  <div class="smoke" style="width:20px;height:20px;margin-top:-2px;margin-left:10px;"></div>
  <div class="smoke" style="width:18px;height:18px;margin-top:0px;margin-left:5px;"></div>
  <div class="smoke" style="width:10px;height:10px;margin-top:-5px;margin-left:30px;"></div>
  <div class="smoke" style="width:15px;height:15px;margin-top:0px;margin-left:20px;"></div>
  <div class="smoke" style="width:20px;height:20px;margin-top:-2px;margin-left:15px;"></div>
  <div class="smoke" style="width:8px;height:8px;margin-top:-5px;margin-left:13px;"></div>
  <div class="smoke" style="width:12px;height:12px;margin-top:-5px;margin-left:8px;"></div>
  <div class="smoke" style="width:8px;height:8px;margin-top:0px;margin-left:22px;"></div>
  <div class="smoke" style="width:15px;height:15px;margin-top:-2px;margin-left:5px;"></div>
  <div class="smoke" style="width:20px;height:20px;margin-top:-5px;margin-left:15px;"></div>
  <div class="smoke" style="width:15px;height:15px;margin-top:-2px;margin-left:5px;"></div>
  <div class="smoke" style="width:12px;height:12px;margin-top:-5px;margin-left:8px;"></div>
  <div class="smoke" style="width:8px;height:8px;margin-top:0px;margin-left:30px;"></div>
  <div class="smoke" style="width:20px;height:20px;margin-top:-2px;margin-left:10px;"></div>
  <div class="smoke" style="width:8px;height:8px;margin-top:0px;margin-left:10px;"></div>
  <div class="smoke" style="width:15px;height:15px;margin-top:0px;margin-left:15px;"></div>
  <div class="smoke" style="width:20px;height:20px;margin-top:-5px;margin-left:10px;"></div>
  <div class="smoke" style="width:8px;height:8px;margin-top:-2px;margin-left:30px;"></div>
  <div class="smoke" style="width:10px;height:10px;margin-top:-2px;margin-left:15px;"></div>
  <div class="smoke" style="width:15px;height:15px;margin-top:-0px;margin-left:20px;"></div>

</div>


And you'll see their red outlines even if they're not visible after the glowing tip otherwise.


Now, at random, have each div styled using smoke1 or smoke2.
<div id="empty">
  <div class="smoke smoke1" style="width:15px;height:15px;margin-top:5px;margin-left:25px;"></div>
  <div class="smoke smoke1" style="width:20px;height:20px;margin-top:-2px;margin-left:10px;"></div>
  <div class="smoke smoke2" style="width:18px;height:18px;margin-top:0px;margin-left:5px;"></div>
  <div class="smoke smoke1" style="width:10px;height:10px;margin-top:-5px;margin-left:30px;"></div>
  <div class="smoke smoke2" style="width:15px;height:15px;margin-top:0px;margin-left:20px;"></div>
  <div class="smoke smoke2" style="width:20px;height:20px;margin-top:-2px;margin-left:15px;"></div>
  <div class="smoke smoke1" style="width:8px;height:8px;margin-top:-5px;margin-left:13px;"></div>
  <div class="smoke smoke2" style="width:12px;height:12px;margin-top:-5px;margin-left:8px;"></div>
  <div class="smoke smoke1" style="width:8px;height:8px;margin-top:0px;margin-left:22px;"></div>
  <div class="smoke smoke2" style="width:15px;height:15px;margin-top:-2px;margin-left:5px;"></div>
  <div class="smoke smoke2" style="width:20px;height:20px;margin-top:-5px;margin-left:15px;"></div>
  <div class="smoke smoke1" style="width:15px;height:15px;margin-top:-2px;margin-left:5px;"></div>
  <div class="smoke smoke2" style="width:12px;height:12px;margin-top:-5px;margin-left:8px;"></div>
  <div class="smoke smoke1" style="width:8px;height:8px;margin-top:0px;margin-left:30px;"></div>
  <div class="smoke smoke2" style="width:20px;height:20px;margin-top:-2px;margin-left:10px;"></div>
  <div class="smoke smoke2" style="width:8px;height:8px;margin-top:0px;margin-left:10px;"></div>
  <div class="smoke smoke1" style="width:15px;height:15px;margin-top:0px;margin-left:15px;"></div>
  <div class="smoke smoke2" style="width:20px;height:20px;margin-top:-5px;margin-left:10px;"></div>
  <div class="smoke smoke1" style="width:8px;height:8px;margin-top:-2px;margin-left:30px;"></div>
  <div class="smoke smoke2" style="width:10px;height:10px;margin-top:-2px;margin-left:15px;"></div>
  <div class="smoke smoke1" style="width:15px;height:15px;margin-top:-0px;margin-left:20px;"></div>
</div>


This is for more animation. These CSS classes each call an animation, with different durations. However, both of these animations will run forever, and alternate back and forth.
.smoke
{
  background-color: rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  box-shadow: 0 0 15px rgba(255, 255, 255, 0.5);
}

.smoke1
{
  animation-name: smokebubble1;
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

.smoke2
{
  animation-name: smokebubble2;
  animation-duration: 3s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}


#burnable
{
  width: 100%;
  height: 250px;
  background-color: rgba(255, 255, 255, 1);
  background: linear-gradient(90deg, rgba(230, 230, 230, 1) 0%, rgba(255, 255, 255, 1) 50%, rgba(230, 230, 230, 1) 100%);
}


Here are their animations. The box-shadow and margin-left properties are animated. I won't bother showing screenshots because the range of motion is rather limited.
.smoke1
{
  animation-name: smokebubble1;
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

.smoke2
{
  animation-name: smokebubble2;
  animation-duration: 3s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

@keyframes smokebubble1
{
  from { box-shadow: 0 0 11px rgba(255, 255, 255, 1); margin-left: 26px; }
}

@keyframes smokebubble2
{
  from { box-shadow: 0 0 12px rgba(255, 255, 255, 0.8); margin-left: 24px; }
}


#burnable
{
  width: 100%;
  height: 250px;
  background-color: rgba(255, 255, 255, 1);
  background: linear-gradient(90deg, rgba(230, 230, 230, 1) 0%, rgba(255, 255, 255, 1) 50%, rgba(230, 230, 230, 1) 100%);
}


In the JavaScript, we define the object idleCounter. In it, there are the properties lastActivity and msToPopup. lastActivity is a timestamp and defaults to null. msToPopup is an integer, defaults to 5, and defines the number of seconds of idle time encountered before the popup happens.
<script>
  var idleCounter =
  {
    lastActivity: null,
    msToPopup: 5
  };

</script>


We then have the method, startTimer(). What it does is set the observeLastActivity() method to run every second.
<script>
  var idleCounter =
  {
    lastActivity: null,
    msToPopup: 5,
    startTimer: function()
    {
      setInterval(
        () =>
        {
          this.observeLastActivity();
        }, 
       1000
      );
    }
  };
</script>


And we want this method to run as soon as the page is loaded.
<script>
  var idleCounter =
  {
    lastActivity: null,
    msToPopup: 5,
    startTimer: function()
    {
      setInterval(
        () =>
        {
          this.observeLastActivity();
        },
        5000
      );
    }
  };

  window.onload = () =>
  {
    idleCounter.startTimer();
  };
</script>


Create observeLastActivity(). If lastActivity is falsy (not defined or just null) then we run the setLastActivity() method. We'll run the popup() method regardless.
var idleCounter =
{
  lastActivity: null,
  msToPopup: 5,
  popupOpen: false,
  observeLastActivity: function()
  {
    if (!this.lastActivity) this.setLastActivity();
    this.popup();
  },

  startTimer: function()
  {
    setInterval(
      () =>
      {
        this.observeLastActivity();
      },
      5000
    );
  }
};


So we have two new methods to create. Start with setLastActivity(). This basically involves setting lastActivity to the current time, then running popup().
var idleCounter =
{
  lastActivity: null,
  msToPopup: 5,
  setLastActivity: function()
  {
    this.lastActivity = new Date();
    this.popup();
  },
  observeLastActivity: function()
  {
    if (!this.lastActivity) this.setLastActivity();
    this.popup();
  },
  startTimer: function()
  {
    setInterval(
      () => 
      {
        this.observeLastActivity(); 
     }, 
     5000
    );
  }
};


Now for the popup() method. Define d as the current time. Then use the getTime() method on d and lastActivity to get the number of milliseconds since the first day of 1970, for each timestamp, and subtract to get diff. Of course d will always be greater than lastActivity, even if by a couple milliseconds.
var idleCounter =
{
  lastActivity: null,
  msToPopup: 5,
  popupOpen: false,
  setLastActivity: function()
  {
    this.lastActivity = new Date();
    this.popup();
  },
  observeLastActivity: function()
  {
    if (!this.lastActivity) this.setLastActivity();
    this.popup();
  },
  startTimer: function()
  {
    setInterval(
      () => 
      {
        this.observeLastActivity(); 
     }, 
     5000
    );
  }
  popup: function()
  {
    var d = new Date();
    var diff = d.getTime() - this.lastActivity.getTime();
  }
};


Then divide diff (which is in milliseconds) by 1000 to get the number of seconds. And create a conditional to check if diff is now greater or equal to msToPopup.
popup: function()
{
  var d = new Date();
  var diff = d.getTime() - this.lastActivity.getTime();
  diff = diff / 1000;

  if (diff >= this.msToPopup)
  {

  }
  else
  {

  }

}


Define overlay as the modal, empty as the empty div and burnable as the burnable div. This is where it gets exciting.
popup: function()
{
  var d = new Date();
  var diff = d.getTime() - this.lastActivity.getTime();
  diff = diff / 1000;

  var overlay = document.getElementById("overlay");
  var empty = document.getElementById("empty");
  var burnable = document.getElementById("burnable");


  if (diff >= this.msToPopup)
  {

  }
  else
  {

  }
}


Now if diff is greater or equal to msToPopup, we want to display the modal by setting the display property of its style object to block. By default, we will set empty's height to 50 pixels and burnable's height to 250 pixels. If not, we hide overlay.
popup: function()
{
  var d = new Date();
  var diff = d.getTime() - this.lastActivity.getTime();
  diff = diff / 1000;

  var overlay = document.getElementById("overlay");
  var empty = document.getElementById("empty");
  var burnable = document.getElementById("burnable");

  if (diff >= this.msToPopup)
  {
    overlay.style.display = "block";
    empty.style.height = "50px";
    burnable.style.height = "250px";

  }
  else
  {
    overlay.style.display = "none";
  }
}


Here's the fun part. If diff is greater or equal to twice msToPopup, set empty's height to 80 pixels and burnable's height to 220 pixels. It will still add up to 300 pixels. The effect is that if more idle time has passed, empty will be taller and burnable will be shorter.
popup: function()
{
  var d = new Date();
  var diff = d.getTime() - this.lastActivity.getTime();
  diff = diff / 1000;

  var overlay = document.getElementById("overlay");
  var empty = document.getElementById("empty");
  var burnable = document.getElementById("burnable");

  if (diff >= this.msToPopup)
  {
    overlay.style.display = "block"; 
    empty.style.height = "50px";
    burnable.style.height = "250px";

    if (diff >= (this.msToPopup * 2))
    {
       empty.style.height = "80px";
       burnable.style.height = "220px";
    }
  }
  else
  {
    overlay.style.display = "none";
  }
}


And so on, and so forth. I've set a few cases here and you should feel free to add more.
popup: function()
{
  var d = new Date();
  var diff = d.getTime() - this.lastActivity.getTime();
  diff = diff / 1000;

  var overlay = document.getElementById("overlay");
  var empty = document.getElementById("empty");
  var burnable = document.getElementById("burnable");

  if (diff >= this.msToPopup)
  {
    overlay.style.display = "block";
    empty.style.height = "50px";
    burnable.style.height = "250px";

    if (diff >= (this.msToPopup * 2))
    {
       empty.style.height = "80px";
       burnable.style.height = "220px";
    }

    if (diff >= (this.msToPopup * 3))
    {
       empty.style.height = "100px";
       burnable.style.height = "200px";
    }

    if (diff >= (this.msToPopup * 5))
    {
       empty.style.height = "200px";
       burnable.style.height = "100px";
    }

    if (diff >= (this.msToPopup * 10))
    {
       empty.style.height = "250px";
      burnable.style.height = "50px";
    }

  }
  else
  {
    overlay.style.display = "none";
  }
}


And while we're at it, disable the red outline.
div { outline: 0px solid red; }


When you first refresh the browser, there should be no modal because the popup() method detects that 5 seconds of inactivity have not passed, so the modal remains invisible. Wait for 5 seconds, and it should come up!


At 10 seconds, the cigarette grows shorter.


At 15 seconds...


At 25 seconds...


At 50 seconds...


For the final touch, add these two lines. This ensures that if you move the mouse or press a keyboard button, setLastActivity() gets run and will result in the modal disappearing until another 5 seconds of inactivity passes.
window.onload = () =>
{
  idleCounter.startTimer();

  document.body.addEventListener("keypress", ()=> { idleCounter.setLastActivity(); });
  document.body.addEventListener("mousemove", ()=> { idleCounter.setLastActivity(); });

};


Well done!

We just implemented a browser screen saver. Cool, right?!

Don't be idle now!
T___T