Skip to content

Instantly share code, notes, and snippets.

@primaryobjects
Last active August 8, 2025 01:37
Show Gist options
  • Save primaryobjects/5f2897fd0e1aaa77018d4fd9e542116c to your computer and use it in GitHub Desktop.
Save primaryobjects/5f2897fd0e1aaa77018d4fd9e542116c to your computer and use it in GitHub Desktop.
I Shall Fear No Evil (Robert A. Heinlein book review) https://jsbin.com/dirirucuha/edit?html,css,output

I Shall Fear No Evil

Book Review

Animation

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>I Shall Fear No Evil</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="stars"></canvas>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<div class="content">
<h1>I SHALL FEAR<br>NO EVIL</h1>
<div class="baby-container">
<div class="aura-rotate">
<div class="aura"></div>
</div>
<img src="https://hotlinkimagehosting.com/uploads/68/86/6886aa8b5ce4d0bf.png" alt="Baby Silhouette" class="baby">
<div class="aura2-rotate">
<div class="aura2"></div>
</div>
</div>
<p class="rating">3/5 ★ — IDENTITY REBORN</p>
</div>
<script src="script.js"></script>
</body>
</html>
const canvas = document.getElementById('stars');
const ctx = canvas.getContext('2d');
let stars = [];
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function createStars(count) {
stars = [];
for (let i = 0; i < count; i++) {
stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
radius: Math.random() * 1.5,
alpha: Math.random(),
delta: Math.random() * 0.02
});
}
}
function drawStars() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "white";
for (let star of stars) {
ctx.globalAlpha = star.alpha;
ctx.beginPath();
ctx.arc(star.x, star.y, star.radius, 0, Math.PI * 2);
ctx.fill();
// Twinkle
star.alpha += star.delta;
if (star.alpha <= 0 || star.alpha >= 1) {
star.delta = -star.delta;
}
}
requestAnimationFrame(drawStars);
}
window.addEventListener('resize', () => {
resizeCanvas();
createStars(200);
});
resizeCanvas();
createStars(200);
drawStars();
html, body {
margin: 0;
padding: 0;
background: black;
overflow: hidden;
height: 100%;
font-family: Arial, sans-serif;
color: white;
text-align: center;
}
h1, .rating {
font-family: 'Press Start 2P', monospace;
text-transform: uppercase;
text-shadow:
0 0 2px #fff,
0 0 4px #0ff,
0 0 8px #0ff,
0 0 16px #0ff;
padding: 60px;
}
#stars {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.content {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
h1 {
font-size: 3em;
font-weight: bold;
margin-bottom: 20px;
letter-spacing: 2px;
}
.baby-container {
position: relative;
width: 200px;
height: 300px;
z-index: 1;
}
/* Make sure aura containers go behind the baby */
.aura-rotate,
.aura2-rotate {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 0;
}
.aura2-rotate {
position: absolute;
top: 55%;
left: 50%;
animation: spin 10s linear infinite;
z-index: 3; /* Ensure it's above the baby */
}
.aura2 {
z-index: 3; /* Ensure this matches or exceeds aura2-rotate */
}
.baby {
position: absolute;
z-index: 2; /* Lower than the aura */
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 100%;
}
@keyframes pulse-slow {
0%, 100% {
opacity: 0.8;
transform: translate(-50%, -50%) scale(1);
}
50% {
opacity: 0.4;
transform: translate(-50%, -50%) scale(1.15);
}
}
/* Rotation animation */
@keyframes spin {
from { transform: translate(-50%, -50%) rotate(0deg); }
to { transform: translate(-50%, -50%) rotate(360deg); }
}
/* Wrapper for outer aura */
.aura-rotate {
position: absolute;
top: 50%;
left: 50%;
animation: spin 20s linear infinite; /* slow rotation */
}
/* Wrapper for chest aura */
.aura2-rotate {
position: absolute;
top: 55%;
left: 50%;
animation: spin 10s linear infinite; /* chest glow rotates faster */
}
/* Chest aura with heartbeat */
.aura2 {
width: 110px;
height: 110px;
background: radial-gradient(circle,
rgba(255,0,0,1) 0%,
rgba(255,69,0,1) 15%,
rgba(255,165,0,1) 30%,
rgba(255,255,0,1) 45%,
rgba(0,255,0,1) 60%,
rgba(0,0,255,1) 75%,
rgba(75,0,130,1) 85%,
rgba(148,0,211,1) 95%,
rgba(0,0,0,0) 100%);
border-radius: 50%;
animation: heartbeat 1.8s infinite ease-in-out;
filter: blur(20px);
opacity: 0.9;
pointer-events: none;
}
.aura {
position: absolute;
top: 50%;
left: 50%;
width: 320px;
height: 320px;
background: radial-gradient(circle,
rgba(255,0,0,1) 0%,
rgba(255,165,0,1) 15%,
rgba(255,255,0,1) 30%,
rgba(0,255,0,1) 45%,
rgba(0,0,255,1) 60%,
rgba(75,0,130,1) 75%,
rgba(148,0,211,1) 90%,
rgba(0,0,0,0) 100%);
border-radius: 50%;
transform: translate(-50%, -50%);
animation: pulse 3s infinite ease-in-out;
filter: blur(35px);
opacity: 0.85;
}
/* Keep existing aura styles but remove absolute position from them */
.aura {
width: 320px;
height: 320px;
background: radial-gradient(circle,
rgba(255,0,0,1) 0%,
rgba(255,69,0,1) 15%,
rgba(255,165,0,1) 30%,
rgba(255,255,0,1) 45%,
rgba(0,255,0,1) 60%,
rgba(0,0,255,1) 75%,
rgba(75,0,130,1) 85%,
rgba(148,0,211,1) 95%,
rgba(0,0,0,0) 100%);
border-radius: 50%;
animation: pulse 3s infinite ease-in-out;
filter: blur(35px);
opacity: 0.85;
}
.aurapix, .aura2pix {
image-rendering: pixelated;
filter: none; /* remove blur */
}
/* Heartbeat double-tap pulse */
@keyframes heartbeat {
0% {
opacity: 0.9;
transform: translate(-50%, -50%) scale(1);
}
10% {
opacity: 1;
transform: translate(-50%, -50%) scale(1.18);
}
20% {
opacity: 0.85;
transform: translate(-50%, -50%) scale(1.05);
}
30% {
opacity: 1;
transform: translate(-50%, -50%) scale(1.15);
}
40% {
opacity: 0.85;
transform: translate(-50%, -50%) scale(1);
}
100% {
opacity: 0.85;
transform: translate(-50%, -50%) scale(1);
}
}
.aura {
animation: pulse 3s infinite ease-in-out;
background: radial-gradient(circle,
rgba(255,0,0,1) 0%, /* Strong red */
rgba(255,69,0,1) 15%, /* Strong orange-red */
rgba(255,165,0,1) 30%, /* Strong orange */
rgba(255,255,0,1) 45%, /* Strong yellow */
rgba(0,255,0,1) 60%, /* Strong green */
rgba(0,0,255,1) 75%, /* Strong blue */
rgba(75,0,130,1) 85%, /* Indigo */
rgba(148,0,211,1) 95%, /* Violet */
rgba(0,0,0,0) 100%);
}
.aura2 {
position: absolute;
top: 55%;
left: 50%;
width: 110px;
height: 110px;
background: radial-gradient(circle,
rgba(255,0,0,1) 0%, /* Strong red */
rgba(255,69,0,1) 15%, /* Strong orange-red */
rgba(255,165,0,1) 30%, /* Strong orange */
rgba(255,255,0,1) 45%, /* Strong yellow */
rgba(0,255,0,1) 60%, /* Strong green */
rgba(0,0,255,1) 75%, /* Strong blue */
rgba(75,0,130,1) 85%, /* Indigo */
rgba(148,0,211,1) 95%, /* Violet */
rgba(0,0,0,0) 100%);
border-radius: 50%;
transform: translate(-50%, -50%);
animation: heartbeat 1.8s infinite ease-in-out;
filter: blur(20px);
opacity: 0.9;
pointer-events: none;
}
@keyframes pulse {
0%, 100% {
opacity: 0.7;
transform: translate(-50%, -50%) scale(1);
}
50% {
opacity: 0.4;
transform: translate(-50%, -50%) scale(1.2);
}
}
.baby {
position: absolute;
z-order: 100;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 100%;
}
.rating {
font-size: 1.2em;
margin-top: 20px;
letter-spacing: 2px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment