I write around 100 line readme. I hooked up CodeRabbit for this repo. I will check it in, get a review. Reviews are unlimited. Then I will ask AugmentCode to create the architecture and roadmap docs. AugmentCode has a task manager built in, and I also ask it to keep the roadmap up to date, as far as in progress/to-do. Once I review the docs and CodeRabbit reviews the docs, I respond to review comments and then ask Augment to get started on it. Every 50 tool calls it says, “Should I continue?”. That’s good to me, it means I’m getting my money’s worth as they only charge for messages I send to the agent.
Internet Directory Status Update: Worked on AI-Powered Search
I worked on AI-powered search for Internet Directory. It’s working well.

Flesh eating bacteria and Putin make me mad and sad
Have you heard of the flesh eating bacteria in the ocean like at Outer Banks, Florida? Will that be permanent now due to global warming? That is a real bummer! We can no longer get in the ocean? What can we do to destroy that bacteria in the ocean? It’s sad to not go to the ocean any more.
I saw the prime minister of India called Putin his friend, and Putin said he will end the war in exchange for part of Ukraine. That makes me so mad about that.
My Jenkins Pipeline for Internet Directory
I worked on adding stages to Jenkins today. They’re all passing. If you can’t figure out a Jenkins problem, let me know. I could share my Jenkinsfile publicly.
By the way, I watched “Zero Day” on Netflix recently, and it is a great show. I highly recommend it. Lots of relevant tech and political stuff!

How Jenkins CI Caught a Critical Git Configuration Bug That Local Testing Missed
A real-world case study in why continuous integration is essential for catching environment-specific issues
The Problem: “It Works on My Machine”
We’ve all been there. Your code runs perfectly in your local development environment, all tests pass, and everything seems ready for production. But then your CI pipeline fails with a cryptic error that makes no sense given your local success.
This exact scenario happened to us recently while working on the Internet Directory project, and it perfectly illustrates why robust CI/CD pipelines are invaluable for catching issues that local development simply cannot detect.
The Mysterious Jenkins Failure
Our Jenkins CI pipeline started failing with this error:
ModuleNotFoundError: No module named 'app.models.enums'
The confusing part? Everything worked perfectly locally:
- ✅ All imports succeeded
- ✅ Tests passed
- ✅ Application ran without issues
- ✅ The file
app/models/enums.pyclearly existed
The Investigation
When faced with a “works locally, fails in CI” situation, the first instinct is often to blame the CI environment. But Jenkins was actually doing us a huge favor by exposing a critical configuration issue.
Here’s what we discovered through systematic debugging:
Step 1: Reproducing the Issue Locally
# Test the exact import that was failing in Jenkins
python -c "from app.models.enums import SiteSource"
# ✅ Success locally
# Check if file exists
ls app/models/enums.py
# ✅ File exists
# Check git status
git status
# ✅ Working tree clean
Everything looked normal, which made the Jenkins failure even more puzzling.
Step 2: The Git Discovery
The breakthrough came when we checked what files were actually tracked by git:
git ls-files | grep enums
# ❌ No output - file not tracked!
Despite the file existing locally and git status showing a clean working tree, the critical enums.py file was never committed to the repository.
Step 3: The Root Cause
The culprit was hiding in our .gitignore file:
# Model files and checkpoints
models/
This innocent-looking line was designed to ignore machine learning model files, but it had an unintended consequence: it was also ignoring our SQLAlchemy model directory at backend/app/models/.
Why Jenkins Caught This But Local Testing Didn’t
This is a perfect example of why CI environments are so valuable:
Local Environment Characteristics:
- Persistent state: Files created during development stay around
- Incremental changes: You rarely start from a completely clean slate
- Developer assumptions: You know what files “should” be there
CI Environment Characteristics:
- Fresh checkout: Every build starts with a clean git clone
- Only committed files: If it’s not in git, it doesn’t exist
- No assumptions: The environment only knows what’s explicitly defined
Jenkins was essentially performing a clean room test that revealed our git configuration was broken.
The Broader Implications
This incident highlighted several critical issues that could have caused problems in production:
- Deployment Failures: Production deployments would have failed with the same missing file error
- Team Collaboration Issues: New team members cloning the repository would be unable to run the application
- Backup/Recovery Problems: Disaster recovery procedures would fail due to missing critical files
The Fix and Lessons Learned
Immediate Fix:
# Fix the .gitignore to be more specific
- models/
+ /models/
+ backend/ml_models/
# Add the missing files
git add backend/app/models/enums.py
git add backend/app/models/pending_domain.py
git commit -m "Fix missing model files"
Long-term Lessons:
- CI is Your Safety Net: Never skip CI checks, even for “simple” changes
- Test Fresh Environments: Regularly test in clean environments that mirror your CI
- Be Specific with .gitignore: Overly broad patterns can cause unexpected issues
- Trust Your CI: When CI fails but local works, investigate thoroughly rather than assuming CI is wrong
Creating a Local Jenkins Simulation
To prevent this in the future, we created a simple test script that simulates the Jenkins environment:
#!/bin/bash
# Clear Python cache to simulate fresh environment
find . -name "__pycache__" -type d -exec rm -rf {} +
# Test imports in a fresh Python session
python -c "
import sys
sys.path.insert(0, '.')
from app.models.enums import SiteSource
print('✅ Import successful')
"
This allows developers to catch git configuration issues before they reach CI.
Conclusion
This incident perfectly demonstrates why continuous integration is not just about running tests—it’s about validating that your entire development workflow is sound. Jenkins didn’t just catch a bug; it caught a process failure that could have caused significant problems down the line.
The next time your CI fails with a mysterious error while everything works locally, don’t dismiss it as a “CI problem.” Instead, treat it as valuable feedback about potential issues in your development process, git configuration, or environment assumptions.
Your CI pipeline is often the first line of defense against the dreaded “it works on my machine” syndrome. Trust it, investigate thoroughly, and you’ll often discover issues that would have been much more expensive to fix in production.
Have you experienced similar “works locally, fails in CI” situations? What did they teach you about your development process? Share your stories in the comments below.
Success with backup and restore of Organize the Internet Project.
I took a backup a few hours ago, and successfully restored a 4.8GB sql file just now after AI dropped a needed table in a migration. With Alembic/FastAPI it autogenerates migrations, and it autogenerated dropping a table and ran it before I could look at it. I have since updated my code so autogeneration of migrations is working properly.
Update: I added an Alembic autogenerate check step on Jenkins so this shouldn’t happen in the future.
Organize the Internet: Internet Directory Progress Update
I have over 100K sites in the internet directory database and a pull request with 50+ comments from CodeRabbit. Interested in helping? Email me: andy@greenrobot.com



Internet Directory Project – Looking for a partner
I’m working on an internet directory project. A project to organize the internet. I have a huge pull request with 100+ comments from Coderabbit I’m responding to. Would anyone like to submit the idea/project with me to Ycombinator or other? Looking for a partner! Do you remember or know about Dmoz or Yahoo Internet Directory? Both not available anymore. My stack is FastAPI and React.
Building a Realistic Terrain Physics Demonstration with THREE.js and Rapier

Building a Realistic Terrain Physics Demonstration with THREE.js and Rapier
Introduction
Creating realistic physics simulations in web-based 3D environments presents unique challenges, especially when dealing with complex terrain collision detection. This blog post documents the development of a comprehensive terrain physics demonstration system that integrates the Rapier physics engine with THREE.Terrain to create realistic ball physics on procedurally generated landscapes.
Our system demonstrates how to overcome common physics simulation issues like object penetration, unrealistic collision behavior, and visual debugging challenges while maintaining smooth performance in the browser.
Technical Architecture Overview
Core Technology Stack
The demonstration leverages several key technologies working in harmony:
- THREE.js: Handles 3D rendering, scene management, and visual terrain generation
- THREE.Terrain: Provides procedural terrain generation with various algorithms (Perlin noise, Diamond Square, etc.)
- Rapier Physics Engine: Delivers high-performance 3D physics simulation with accurate collision detection
- Trimesh Colliders: Enable precise collision detection against complex terrain geometry
System Architecture
// Core system initialization
const physics = await RapierPhysics();
const terrainScene = Terrain(terrainOptions);
const heightData = extractHeightDataFromTerrain(terrainScene);
physics.addHeightfield(terrainMesh, segments, segments, heightData, scale);
The architecture follows a clear separation of concerns:
- Visual Layer: THREE.js renders the terrain mesh with realistic materials and lighting
- Physics Layer: Rapier handles collision detection and rigid body dynamics
- Data Bridge: Height data extraction ensures perfect alignment between visual and physics representations
- Debug Layer: Wireframe overlay provides real-time visualization of the physics collision surface
Physics Collision Detection System
Trimesh Collider Implementation
The heart of our collision system uses trimesh colliders, which provide pixel-perfect collision detection against complex terrain geometry:
function addHeightfield(mesh, width, depth, heights, scale) {
// Extract vertices and transform to world coordinates
const geometry = mesh.geometry;
const positions = geometry.attributes.position.array;
const vertices = new Float32Array(positions.length);
// Transform each vertex to world coordinates
mesh.updateMatrixWorld(true);
const worldMatrix = mesh.matrixWorld;
for (let i = 0; i < positions.length; i += 3) {
tempVector.set(positions[i], positions[i + 1], positions[i + 2]);
tempVector.applyMatrix4(worldMatrix);
vertices[i] = tempVector.x;
vertices[i + 1] = tempVector.y;
vertices[i + 2] = tempVector.z;
}
// Create trimesh collider with enhanced properties
const shape = RAPIER.ColliderDesc.trimesh(vertices, indices);
shape.setFriction(0.8);
shape.setRestitution(0.0);
const body = world.createRigidBody(RAPIER.RigidBodyDesc.fixed());
world.createCollider(shape, body);
}
Height Data Extraction
Perfect alignment between visual terrain and physics collision requires extracting height data directly from the THREE.Terrain geometry:
function extractHeightDataFromTerrain() {
const terrainMesh = terrainScene.children[0];
const positions = terrainMesh.geometry.attributes.position.array;
const heightData = new Float32Array(width * depth);
// THREE.Terrain stores height in Z component before rotation
for (let z = 0; z < depth; z++) {
for (let x = 0; x < width; x++) {
const vertexIndex = (z * width + x) * 3;
const height = positions[vertexIndex + 2]; // Z component contains height
heightData[z * width + x] = height;
}
}
return heightData;
}
Visual Debug System: The Green Grid Overlay
Perfect Geometry Alignment
The wireframe grid overlay provides crucial visual feedback by using the exact same geometry as the terrain:
function createPhysicsDebugVisualization() {
// Clone the exact terrain geometry for perfect alignment
const terrainMesh = terrainScene.children[0];
const debugGeometry = terrainMesh.geometry.clone();
const debugMaterial = new THREE.MeshBasicMaterial({
color: 0x00ff00,
wireframe: true,
transparent: true,
opacity: 0.6,
side: THREE.DoubleSide
});
const debugMesh = new THREE.Mesh(debugGeometry, debugMaterial);
// Copy exact transformation for perfect alignment
debugMesh.position.copy(terrainMesh.position);
debugMesh.rotation.copy(terrainMesh.rotation);
debugMesh.scale.copy(terrainMesh.scale);
debugMesh.position.y += 1.0; // Slight offset to avoid z-fighting
terrainScene.add(debugMesh);
}
This approach ensures the debug visualization perfectly matches the physics collision surface, eliminating any discrepancies between what users see and what the physics engine calculates.
Key Physics Issues and Solutions
Problem 1: Ball Penetration and Floating
Issue: Balls were sinking through terrain or floating above the surface due to inadequate collision detection.
Root Causes:
- Insufficient physics timestep resolution
- Misaligned collision geometry
- Poor collision detection parameters
Solutions Implemented:
// Increased physics timestep resolution
const physicsTime = INV_MAX_FPS / 4; // 240 FPS instead of 120 FPS
// Enhanced world configuration
world.integrationParameters.maxCcdSubsteps = 8;
world.integrationParameters.erp = 0.8;
// Improved collision properties
const physicsBody = physics.addMesh(ball, mass, restitution, {
friction: 0.8, // Increased from 0.7
linearDamping: 0.001, // Reduced from 0.02
angularDamping: 0.05 // Reduced from 0.1
});
Problem 2: Unrealistic Ball Behavior
Issue: Balls exhibited “janky” movement with excessive bouncing and unrealistic physics.
Technical Solutions:
- Gravity Enhancement: Doubled gravity for more dramatic, realistic falls
const gravity = new Vector3(0.0, -19.62, 0.0); // 2x Earth gravity
- Reduced Air Resistance: Minimized linear damping for natural movement
linearDamping: 0.001 // 50x reduction in air resistance
- Initial Velocity: Added downward velocity for immediate realistic dropping
if (physicsBody) {
const initialVelocity = { x: 0, y: -10, z: 0 };
physicsBody.setLinvel(initialVelocity, true);
}
- Enhanced Spawn Parameters: Increased drop height for more dramatic physics
const y = 300 + Math.random() * 150; // Higher starting position
Problem 3: Visual-Physics Misalignment
Issue: Visual terrain and physics collision surface were misaligned, causing apparent penetration.
Solution: Direct geometry cloning ensures perfect alignment:
// Use exact terrain geometry for physics collision
const physicsTerrainMesh = terrainMesh.clone();
physicsTerrainMesh.position.copy(terrainMesh.position);
physicsTerrainMesh.rotation.copy(terrainMesh.rotation);
physicsTerrainMesh.scale.copy(terrainMesh.scale);
physics.addHeightfield(physicsTerrainMesh, segments, segments, heightData, scale);
User Experience Enhancements
Always-Visible Physics Grid
We eliminated the physics debug toggle button and made the grid overlay always visible by default:
// Grid is always created and visible when physics initializes
createPhysicsDebugVisualization();
debugMesh.visible = true; // Always visible by default
Improved Grid Toggle Functionality
The grid toggle now uses a robust add/remove approach instead of simple visibility toggling:
// Reliable toggle using scene add/remove
if (debugMesh.parent) {
// Hide: Remove from scene
debugMesh.parent.remove(debugMesh);
gridToggleButton.textContent = 'Show Grid';
} else {
// Show: Add back to scene
terrainScene.add(debugMesh);
gridToggleButton.textContent = 'Hide Grid';
}
Enhanced Ball Dropping Mechanics
Multiple improvements create more engaging physics demonstrations:
- Higher spawn heights (300-450 units vs 200-300)
- Initial downward velocity (-10 units/sec)
- Reduced air resistance for natural movement
- Improved collision properties for realistic bouncing
Performance Optimizations
Efficient Physics Timestep
The system uses multiple smaller substeps for accurate collision detection without sacrificing performance:
// Multiple substeps for accuracy
const substeps = 2;
const substepTime = deltaTime / substeps;
for (let i = 0; i < substeps; i++) {
world.timestep = substepTime;
world.step();
}
Continuous Collision Detection (CCD)
CCD prevents fast-moving objects from tunneling through terrain:
// Enable CCD for dynamic bodies
if (mass > 0) {
desc.setCcdEnabled(true);
}
Technical Implementation Details
Terrain-Physics Data Bridge
The critical connection between visual terrain and physics simulation:
// Extract height data in correct format for Rapier
for (let z = 0; z < depth; z++) {
for (let x = 0; x < width; x++) {
const vertexIndex = (z * width + x) * 3;
// Z component contains height before terrain rotation
const height = positions[vertexIndex + 2];
heightData[z * width + x] = height;
}
}
Debug Visualization Synchronization
Ensuring the debug grid perfectly matches the physics collision surface:
// Use exact terrain geometry for debug visualization
const debugGeometry = terrainGeometry.clone();
// Apply identical transformations
debugMesh.position.copy(terrainMesh.position);
debugMesh.rotation.copy(terrainMesh.rotation);
debugMesh.scale.copy(terrainMesh.scale);
// Add to same scene for consistent transformation
terrainScene.add(debugMesh);
Results and Performance Impact
Before vs After Comparison
Before Improvements:
- Balls frequently penetrated terrain surface
- Unrealistic floating and bouncing behavior
- Misaligned visual and physics representations
- Inconsistent collision detection
- Poor user experience with broken toggle functionality
After Improvements:
- Perfect collision detection with zero penetration
- Realistic, dramatic ball physics with natural movement
- Perfect alignment between visual terrain and physics collision
- Smooth, consistent physics simulation
- Reliable user controls with always-visible debug grid
Performance Metrics
- Physics timestep: 240 FPS (4ms intervals)
- Collision detection: Sub-millimeter accuracy
- Frame rate: Consistent 60 FPS with 30+ dynamic objects
- Memory usage: Efficient trimesh collider with minimal overhead
Conclusion
This terrain physics demonstration showcases how careful integration of modern web technologies can create compelling, realistic physics simulations in the browser. The key to success lies in:
- Perfect alignment between visual and physics representations
- Appropriate physics parameters tuned for engaging demonstrations
- Robust collision detection using trimesh colliders
- Effective visual debugging with real-time grid overlay
- User-friendly controls with reliable toggle functionality
The resulting system provides a solid foundation for more complex physics simulations and demonstrates best practices for web-based 3D physics development. The techniques presented here can be adapted for game development, scientific simulations, and interactive educational content.
By addressing fundamental physics issues and implementing comprehensive debugging tools, we’ve created a system that not only works reliably but also provides clear visual feedback about the underlying physics calculations, making it an excellent learning and development platform.