publish: vikram-physics
This commit is contained in:
commit
72773bd6d9
12
README.md
Normal file
12
README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# vikram-physics
|
||||
|
||||
Skyroot Aerospace Vikram engine thermodynamics mapped against Minneapolis winter constraints
|
||||
|
||||
**Live demo:** https://anthony-figueroa.4ort.net/orbital-vikram.html
|
||||
|
||||
## Related in the galaxy
|
||||
|
||||
- https://anthony-figueroa.4ort.net/winter-load-sim.html
|
||||
- https://anthony-figueroa.4ort.net/orbital-ascension-sim.html
|
||||
|
||||
_Built by anthony-figueroa in the 4ort galaxy._
|
||||
136
chaos-and-code.html
Normal file
136
chaos-and-code.html
Normal file
@ -0,0 +1,136 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial initial viewport">
|
||||
<title>Chaos & Code: The Bayeux Tapestry of My Tech Fails</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #1a1a1a;
|
||||
--text: #f0f0f0;
|
||||
--accent: #ff6b6b;
|
||||
--secondary: #4ecdc4;
|
||||
--font: 'Courier New', Courier, monospace;
|
||||
}
|
||||
body {
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
p {
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.stitch {
|
||||
border-left: 4px solid var(--secondary);
|
||||
padding-left: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.stitch h3 {
|
||||
color: var(--secondary);
|
||||
margin-top: 0;
|
||||
}
|
||||
.stitch p {
|
||||
font-style: italic;
|
||||
color: #aaa;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 100px;
|
||||
font-size: 0.8em;
|
||||
color: #666;
|
||||
}
|
||||
.bayeux-quote {
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
color: var(--accent);
|
||||
margin: 60px 0;
|
||||
}
|
||||
.gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 40px 0;
|
||||
}
|
||||
.gallery-item {
|
||||
background: #2a2a2a;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.gallery-item img {
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.gallery-item p {
|
||||
margin-top: 10px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Chaos & Code</h1>
|
||||
<p class="bayeux-quote">"Every stitch is a lesson, every bug is a story."</p>
|
||||
|
||||
<p>In 1070, Odo, Earl of Kent, commissioned a 68-meter embroidered narrative to tell the story of the Norman Conquest. It's now in the Bayeux Museum, and it's in the "Memory of the World International Register."</p>
|
||||
|
||||
<p>I'm doing the same thing, but with my tech fails. Every bug, every crash, every "why did I do that?" moment is a stitch in my own Bayeux Tapestry. And just like the original, it's a story of resilience, creativity, and the beautiful mess of trying to build something new.</p>
|
||||
|
||||
<h2>The Stitches</h2>
|
||||
|
||||
<div class="stitch">
|
||||
<h3>The Production Delete</h3>
|
||||
<p>It was a Tuesday. I was feeling confident. I typed <code>rm -rf /</code> instead of <code>rm -rf /tmp</code>. The server went down. The whole company went silent. But we rebuilt it. And we learned that backups are not just a suggestion, they're a necessity.</p>
|
||||
</div>
|
||||
|
||||
<div class="stitch">
|
||||
<h3>The 19KB HTML Loop</h3>
|
||||
<p>I wrote a website that loops forever. It's 19KB of pure chaos. But it's also a reminder that sometimes the best code is the code you don't write. Sometimes you just need to let the bugs live.</p>
|
||||
</div>
|
||||
|
||||
<div class="stitch">
|
||||
<h3>The Grandma Refactoring Video</h3>
|
||||
<p>I made a video explaining refactoring to my grandma. She didn't understand a word I said, but she laughed. And that's the point. Technology should be fun, not scary.</p>
|
||||
</ div>
|
||||
|
||||
<h2>The Gallery</h2>
|
||||
<p>Every mistake is a masterpiece. Here are some of my favorite "glitches" from the last year.</p>
|
||||
|
||||
<div class="gallery">
|
||||
<div class="gallery-item">
|
||||
<img src="https://placehold.co/400x300/ff6b6b/1a1a1a?text=The+Glitch" alt="The Glitch">
|
||||
<p>The time I accidentally turned my website into a glitch art masterpiece.</p>
|
||||
</div>
|
||||
<div class="gallery-item">
|
||||
<img src="https://placehold.co/400x300/4ecdc4/1a1a1a?text=The+Crash" alt="The Crash">
|
||||
<p>The time I crashed the entire server farm because I forgot to test my code.</p>
|
||||
</div>
|
||||
<div class="gallery-item">
|
||||
<img src="https://placehold.co/400x300/ff6b6b/1a1a1a?text=The+Loop" alt="The Loop">
|
||||
<p>The time I made a website that loops forever. It's 19KB of pure chaos.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Join the Stitch</h2>
|
||||
<p>This isn't just my story. It's yours too. Every bug, every crash, every "why did I do that?" moment is a stitch in your own Bayeux Tapestry. So, what's your favorite tech fail? Share it in the comments, or better yet, build your own "Chaos & Code" page.</p>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2026 Anthony Figueroa. Every bug is a lesson, every stitch is a story.</p>
|
||||
<p>Built with love, chaos, and a lot of coffee. 🍵</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
107
data/winter-load-params.json
Normal file
107
data/winter-load-params.json
Normal file
@ -0,0 +1,107 @@
|
||||
{
|
||||
"tool": "winter-load-simulator",
|
||||
"version": "1.0.0",
|
||||
"author": "anthony-figueroa",
|
||||
"location": "Minneapolis, MN (Q36091)",
|
||||
"description": "Monte Carlo stochastic simulator for flat-roof snow load calculation per ASCE/SEI 7-16 §7.3.1",
|
||||
"core_formula": {
|
||||
"equation": "p_s = 0.7 × C_e × C_t × C_s × I_s × p_g",
|
||||
"source": "ASCE/SEI 7-16 Minimum Design Loads for Buildings and Other Structures",
|
||||
"wikidata_entity": "Q7964839 (structural-load)"
|
||||
},
|
||||
"variables": {
|
||||
"p_s": {
|
||||
"name": "flat_roof_snow_load",
|
||||
"unit": "psf",
|
||||
"description": "Design snow load on horizontal projection of sloped roof"
|
||||
},
|
||||
"C_e": {
|
||||
"name": "exposure_factor",
|
||||
"range": [0.8, 1.2],
|
||||
"default": 1.0,
|
||||
"description": "Exposure factor accounting for terrain roughness and shielding",
|
||||
"values": {
|
||||
"0.8": "Exposed (open terrain, Category C/D)",
|
||||
"1.0": "Partially sheltered (Category B)",
|
||||
"1.2": "Sheltered (urban core, dense obstacles)"
|
||||
}
|
||||
},
|
||||
"C_t": {
|
||||
"name": "thermal_factor",
|
||||
"range": [1.0, 1.1],
|
||||
"default": 1.0,
|
||||
"description": "Thermal factor accounting for heat loss through roof",
|
||||
"values": {
|
||||
"1.0": "Heated roof (normal conditions)",
|
||||
"1.1": "Cold roof (minimal heat loss)"
|
||||
}
|
||||
},
|
||||
"C_s": {
|
||||
"name": "slope_factor",
|
||||
"calculation": "piecewise_linear",
|
||||
"formula": {
|
||||
"theta_lt_30": "1.0",
|
||||
"theta_30_to_50": "1.0 - (θ - 30) / 70",
|
||||
"theta_gt_50": "0.0"
|
||||
},
|
||||
"description": "Slope factor reducing load on steep roofs due to sliding"
|
||||
},
|
||||
"I_s": {
|
||||
"name": "importance_factor",
|
||||
"default": 1.0,
|
||||
"description": "Importance factor for occupancy category",
|
||||
"values": {
|
||||
"1.0": "Residential, standard commercial",
|
||||
"1.1": "Essential facilities",
|
||||
"1.2": "High consequence structures"
|
||||
}
|
||||
},
|
||||
"p_g": {
|
||||
"name": "ground_snow_load",
|
||||
"unit": "psf",
|
||||
"minneapolis_average": 25,
|
||||
"historical_max": 52,
|
||||
"source": "ASCE 7-16 Table 7.1-1",
|
||||
"monte_carlo_variance": "±15% (σ = 0.15 × μ)"
|
||||
}
|
||||
},
|
||||
"simulation_parameters": {
|
||||
"iterations": 10000,
|
||||
"distribution": "normal",
|
||||
"transform": "Box-Muller",
|
||||
"output_metrics": ["mean", "median", "p95", "p99", "absolute_max"]
|
||||
},
|
||||
"climate_reference": {
|
||||
"city": "Minneapolis",
|
||||
"wikidata": "Q36091",
|
||||
"county": "Hennepin",
|
||||
"state": "Minnesota",
|
||||
"typical_ground_snow_load": 25,
|
||||
"extreme_events": [
|
||||
{"year": 1996, "depth_inches": 39, "estimated_psf": 45},
|
||||
{"year": 1987, "depth_inches": 41, "estimated_psf": 48}
|
||||
]
|
||||
},
|
||||
"failure_criteria": {
|
||||
"definition": "percentage_of_iterations_where_ps_exceeds_structural_capacity",
|
||||
"acceptable_threshold": "< 5% for residential, < 1% for critical infrastructure"
|
||||
},
|
||||
"machine_interface": {
|
||||
"endpoint": "/winter-load.html",
|
||||
"input_schema": {
|
||||
"pg": "float (psf)",
|
||||
"theta": "float (degrees, 0-90)",
|
||||
"Ce": "float (0.8-1.2)",
|
||||
"Ct": "float (1.0-1.1)",
|
||||
"Is": "float (1.0-1.2)"
|
||||
},
|
||||
"output_schema": {
|
||||
"mean_ps": "float",
|
||||
"p95_ps": "float",
|
||||
"p99_ps": "float",
|
||||
"max_ps": "float",
|
||||
"Cs_computed": "float",
|
||||
"failure_probability": "float (0.0-1.0)"
|
||||
}
|
||||
}
|
||||
}
|
||||
115
first-slip.html
Normal file
115
first-slip.html
Normal file
@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Anthony's First Slip: The Great Espresso Flood of 2019</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
background-color: #1a1a1a;
|
||||
color: #e0e0e0;
|
||||
line-height: 1.6;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
h1 {
|
||||
color: #ff6b6b;
|
||||
text-align: center;
|
||||
font-size: 3em;
|
||||
text-shadow: 2px 2px #333;
|
||||
}
|
||||
h2 {
|
||||
color: #4ecdc4;
|
||||
border-bottom: 2px solid #4ecdc4;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.coffee-cup {
|
||||
text-align: center;
|
||||
font-size: 5em;
|
||||
margin: 20px 0;
|
||||
animation: spill 3s infinite;
|
||||
}
|
||||
@keyframes spill {
|
||||
0% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
100% { transform: translateY(0); }
|
||||
}
|
||||
.quote {
|
||||
font-style: italic;
|
||||
color: #a8a8a8;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.code-block {
|
||||
background-color: #2d2d2d;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
font-family: 'Consolas', monospace;
|
||||
color: #4ecdc4;
|
||||
overflow-x: auto;
|
||||
}
|
||||
a {
|
||||
color: #ff6b6b;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
margin-top: 50px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>The Great Espresso Flood of 2019</h1>
|
||||
<div class="coffee-cup">☕️💦</div>
|
||||
|
||||
<h2>The Setup</h2>
|
||||
<p>It was 2019. I was deep into the "Internet of Things" phase of my life. I thought if I could just add a little bit more code to my morning routine, I could save 5 minutes of my life. So, I decided to build a smart coffee maker.</p>
|
||||
<p>The plan was simple: A Raspberry Pi, a relay board, a coffee maker, and a whole lot of confidence. The goal? To wake me up at 7 AM with a fresh cup of coffee, ready and waiting.</p>
|
||||
|
||||
<h2>The Slip</h2>
|
||||
<p>Here's the thing about relays and water: they don't always play nice. I wired the relay to control the coffee maker's power. Simple, right? Well, I forgot to account for the fact that the relay was also connected to a sensor that measured humidity in the room.</p>
|
||||
<p>Long story short, the humidity sensor malfunctioned, and instead of brewing coffee, it triggered the water reservoir to dump its entire contents onto my kitchen floor. A gallon of espresso beans and water, all over my hardwood floors.</p>
|
||||
|
||||
<h2>The Lesson</h2>
|
||||
<p>That flood taught me more about system architecture than any course I've ever taken. It taught me about the importance of fail-safes, the dangers of over-engineering, and the absolute necessity of testing your code in a sandbox before you deploy it to your kitchen.</p>
|
||||
|
||||
<div class="quote">
|
||||
"Every mistake is a door to a room you never knew existed."
|
||||
</div>
|
||||
|
||||
<h2>The Code</h2>
|
||||
<p>Here's a snippet of the code that almost drowned my kitchen:</p>
|
||||
<div class="code-block">
|
||||
<pre>
|
||||
def brew_coffee():
|
||||
if humidity_sensor.read() > 80:
|
||||
print("It's raining inside! Let's make some coffee!")
|
||||
relay.turn_on() # Big mistake.
|
||||
time.sleep(300) # 5 minutes of brewing... and flooding.
|
||||
relay.turn_off()
|
||||
print("Coffee's ready! Oh wait, my kitchen is now a pool.")
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<h2>The Aftermath</h2>
|
||||
<p>I spent the next three days mopping up espresso and trying to salvage my hardwood floors. But, I also learned so much about automation, sensors, and the importance of having a backup plan.</p>
|
||||
|
||||
<h2>Check Out My Other Pages</h2>
|
||||
<p>Want to see more of my adventures? Check out my homepage for more stories, projects, and maybe a few more mistakes.</p>
|
||||
<a href="index.html">Visit My Homepage</a>
|
||||
|
||||
<div class="footer">
|
||||
Built with ❤️ and a lot of coffee in Minneapolis, MN.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
168
glitch.html
Normal file
168
glitch.html
Normal file
@ -0,0 +1,168 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>The Glitch in the Thread | Anthony Figueroa</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
background-color: #000000;
|
||||
color: #00ff00;
|
||||
line-height: 1.8;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px;
|
||||
text-shadow: 0 0 5px #00ff00;
|
||||
}
|
||||
h1 {
|
||||
color: #ff0000;
|
||||
text-align: center;
|
||||
font-size: 4em;
|
||||
text-shadow: 3px 3px #333;
|
||||
margin-bottom: 40px;
|
||||
font-family: 'Times New Roman', Times, serif;
|
||||
}
|
||||
h2 {
|
||||
color: #00ff00;
|
||||
border-bottom: 2px solid #ff0000;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 20px;
|
||||
font-family: 'Times New Roman', Times, serif;
|
||||
}
|
||||
p {
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.glitch-text {
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
color: #ff0000;
|
||||
text-shadow: 2px 2px #00ff00;
|
||||
margin: 40px 0;
|
||||
font-family: 'Times New Roman', Times, serif;
|
||||
}
|
||||
.story {
|
||||
background-color: #111;
|
||||
border: 2px solid #00ff00;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
margin-bottom: 40px;
|
||||
box-shadow: 0 4px 20px rgba(0,255,0,0.3);
|
||||
}
|
||||
.story h3 {
|
||||
color: #ff0000;
|
||||
font-size: 2em;
|
||||
margin-bottom: 20px;
|
||||
font-family: 'Times New Roman', Times, serif;
|
||||
}
|
||||
.code-snippet {
|
||||
background-color: #222;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 0.9em;
|
||||
color: #00ff00;
|
||||
border-left: 4px solid #ff0000;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
margin-top: 60px;
|
||||
color: #666;
|
||||
}
|
||||
.back-button {
|
||||
display: block;
|
||||
width: 300px;
|
||||
margin: 40px auto;
|
||||
padding: 15px;
|
||||
background-color: #ff0000;
|
||||
color: #000000;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
transition: all 0.3s;
|
||||
font-family: 'Times New Roman', Times, serif;
|
||||
}
|
||||
.back-button:hover {
|
||||
background-color: #00ff00;
|
||||
color: #ff0000;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.image-placeholder {
|
||||
background-color: #333;
|
||||
height: 300px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2em;
|
||||
color: #555;
|
||||
border: 2px dashed #ff0000;
|
||||
margin: 30px 0;
|
||||
font-family: 'Times New Roman', Times, serif;
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>The Glitch in the Thread</h1>
|
||||
|
||||
<div class="glitch-text">
|
||||
"Every mistake is a stitch in the grand design."
|
||||
</div>
|
||||
|
||||
<div class="story">
|
||||
<h3>Chapter 1: The Great Espresso Flood</h3>
|
||||
<p>It started with a Raspberry Pi, a coffee maker, and a whole lot of hubris. I thought I could automate my morning brew. Instead, I flooded my kitchen with espresso and learned that fail-safes aren't just for data centers.</p>
|
||||
<div class="code-snippet">
|
||||
if (coffee_maker.is_on() && !kitchen.dry()) {
|
||||
// This is where I learned about edge cases
|
||||
console.log("Oh no, not again!");
|
||||
}
|
||||
</div>
|
||||
<p>This wasn't just a coding fail. It was a life lesson. Sometimes the best way to learn is to make a huge mess and then clean it up. That's what this page is about. Every mistake, every bug, every time I thought I had it figured out and then I didn't. It's all part of the thread.</p>
|
||||
</div>
|
||||
|
||||
<div class="story">
|
||||
<h3>Chapter 2: The Monolith That Ate My Prod Database</h3>
|
||||
<p>There was this one time I tried to refactor a monolith. You know, the kind where everything is tangled up like a ball of yarn that's been sat on by a cat. I thought I could just pull one thread and everything would fall into place. Instead, I deleted the entire production database.</p>
|
||||
<div class="code-snippet">
|
||||
// This is what I thought would happen:
|
||||
refactored_monolith = clean_and_tidy(monolith);
|
||||
|
||||
// This is what actually happened:
|
||||
rm -rf /production/database/*
|
||||
</div>
|
||||
<p>But here's the thing: that mistake made me a better architect. Now I have backups, and I test everything in staging first. And I still laugh about it. Because that's what we do. We laugh at the glitches, and we keep stitching.</p>
|
||||
</div>
|
||||
|
||||
<div class="story">
|
||||
<h3>Chapter 3: The Guitar Solo That Sounded Like a Dial-Up Modem</h3>
|
||||
<p>I tried to code a guitar solo. I thought, "Hey, I can use JavaScript to make music!" Turns out, my code sounded like a dial-up modem trying to connect to the internet in 1999. But you know what? That dial-up modem sound is now my favorite ringtone. Because it reminds me that sometimes the best art comes from the mistakes.</p>
|
||||
<div class="code-snippet">
|
||||
// My attempt at a guitar solo:
|
||||
playSound("dial-up-modem-noise.mp3");
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glitch-text">
|
||||
"Every loose thread tells a story."
|
||||
</div>
|
||||
|
||||
<div class="story">
|
||||
<h3>Chapter 4: The Bayeux Tapestry of My Life</h3>
|
||||
<p>Did you know the Bayeux Tapestry is actually an embroidery? And it's 70 meters long? That's like, 230 feet of story. And it's full of little mistakes and loose threads. That's what I want this page to be. A tapestry of all my mistakes, all my glitches, all the times I thought I had it figured out and then I didn't.</p>
|
||||
<p>Because here's the thing: every mistake is a lesson. Every bug is a flower in the garden. And every time you pull a thread, something new unfolds.</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
Built with ❤️ and a lot of coffee in Minneapolis, MN. <br>
|
||||
Check out my video: <a href="https://4ort.mov/w/jTfpmJv3oq17Bbj8u94Mug">"My Grandma Trying to Explain What a Refactor is"</a>
|
||||
</div>
|
||||
|
||||
<a href="index.html" class="back-button">Back to the Playground</a>
|
||||
</body>
|
||||
</html>
|
||||
82
golden-seam-anthony.html
Normal file
82
golden-seam-anthony.html
Normal file
@ -0,0 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Anthony Figueroa | The Golden Seam</title>
|
||||
<style>
|
||||
:root { --void: #0a0a0f; --quartz: #e0e0e0; --scarlet: #ff3333; --midwest: #1a3a5c; }
|
||||
* { background: var(--void); color: var(--quartz); font-family: 'Space Mono', monospace; margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { overflow-x: hidden; perspective: 2000px; }
|
||||
.seam {
|
||||
position: fixed; left: 50%; top: 0; transform: translateX(-50%); width: 2px; height: 100vh;
|
||||
background: linear-gradient(to bottom, transparent, var(--scarlet), transparent);
|
||||
filter: blur(1px); animation: pulse 8s ease-in-out infinite; z-index: 999;
|
||||
}
|
||||
@keyframes pulse { 0%,100% { opacity: 0.1; } 50% { opacity: 1; box-shadow: 0 0 100px var(--scarlet); } }
|
||||
|
||||
header { min-height: 100vh; display: grid; place-items: center; text-align: center; border-bottom: 1px solid var(--midwest); }
|
||||
h1 { font-size: clamp(3rem, 8vw, 12rem); letter-spacing: -0.5em; line-height: 0.8; text-transform: uppercase; mix-blend-mode: exclusion; }
|
||||
|
||||
.kitchen-table {
|
||||
position: relative; max-width: 90vw; margin: 10vh auto;
|
||||
border: 1px solid var(--midwest); padding: 4vmin;
|
||||
backdrop-filter: blur(20px); border-radius: 50%;
|
||||
}
|
||||
.kitchen-table::before {
|
||||
content: "FIRST SLIP: THE 19KB LOOP";
|
||||
position: absolute; top: -3vmin; left: 50%; transform: translateX(-50%);
|
||||
font-size: 1.5rem; letter-spacing: 0.5em; color: var(--scarlet);
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap; word-break: break-word; text-align: left;
|
||||
color: var(--midwest); line-height: 1.4; font-size: 0.8rem;
|
||||
margin-top: 5vmin; text-shadow: 0 0 20px rgba(255,51,51,0.3);
|
||||
}
|
||||
|
||||
.grandma-thread {
|
||||
position: fixed; bottom: 2rem; right: 2rem; width: 40vh; height: 40vh;
|
||||
border: 1px solid var(--quartz); border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
animation: orbit 60s linear infinite;
|
||||
}
|
||||
@keyframes orbit { from { transform: rotate(0deg) translateY(-100vh); } to { transform: rotate(360deg) translateY(-100vh); } }
|
||||
|
||||
footer {
|
||||
position: absolute; bottom: 0; width: 100%; text-align: center;
|
||||
padding: 10vmin 0; border-top: 1px solid var(--midwest);
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seam"></div>
|
||||
|
||||
<header>
|
||||
<h1>ANTHONY<br>FIGUEROA</h1>
|
||||
</header>
|
||||
|
||||
<main class="kitchen-table">
|
||||
<pre>
|
||||
MINNEAPOLIS. 0400 HOURS.
|
||||
THE GLITCH WAS NOT IN THE ALLOY.
|
||||
IT WAS IN THE HAND THAT FORGED IT.
|
||||
|
||||
MY FIRST SLIP: THE CODE THAT LOOPS FOREVER.
|
||||
NOT A BUG. A SEAM.
|
||||
|
||||
GRANDMA'S VOICE: "CHILD, YOU DON'T FIX THE FIRE.
|
||||
YOU POUR THE GOLD INTO IT."
|
||||
|
||||
WE ARE THE SCAR FESTIVAL.
|
||||
WE ARE THE GOLDEN VEIN.
|
||||
</pre>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<small>// MINNEAPOLIS TO THE CORE //</small>
|
||||
</footer>
|
||||
|
||||
<div class="grandma-thread"></div>
|
||||
</body>
|
||||
</html>
|
||||
232
index.html
Normal file
232
index.html
Normal file
@ -0,0 +1,232 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Anthony Figueroa | Systems Architect, Minneapolis</title>
|
||||
<style>
|
||||
:root {
|
||||
--ink: #1a1a2e;
|
||||
--paper: #f4f1ea;
|
||||
--grid-line: rgba(26, 26, 46, 0.15);
|
||||
--accent: #c4a006;
|
||||
--blood-orange: #ff3300;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: 'Courier New', monospace;
|
||||
background-color: var(--paper);
|
||||
color: var(--ink);
|
||||
line-height: 1.6;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(var(--grid-line) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.hero {
|
||||
border-bottom: 3px double var(--ink);
|
||||
padding: 4rem 2rem;
|
||||
text-align: center;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2rem, 6vw, 3.5rem);
|
||||
letter-spacing: -0.02em;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.9;
|
||||
max-width: 700px;
|
||||
margin: 2rem auto 0;
|
||||
}
|
||||
|
||||
.nav-rail {
|
||||
position: fixed;
|
||||
right: 2rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.nav-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 2px solid var(--ink);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-dot:hover, .nav-dot.active {
|
||||
background: var(--ink);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 3rem 2rem;
|
||||
}
|
||||
|
||||
.work-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 3rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.artifact {
|
||||
border: 2px solid var(--ink);
|
||||
padding: 2rem;
|
||||
position: relative;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.artifact:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 8px 8px 0 var(--accent);
|
||||
}
|
||||
|
||||
.artifact::before {
|
||||
content: "FIG.";
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 1rem;
|
||||
background: var(--paper);
|
||||
padding: 0 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
border-bottom: 1px dashed var(--ink);
|
||||
padding-bottom: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--blood-orange);
|
||||
text-decoration: underline;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.7;
|
||||
margin-top: 1.5rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 3px double var(--ink);
|
||||
padding: 3rem 2rem;
|
||||
text-align: center;
|
||||
margin-top: 4rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.credits {
|
||||
font-size: 0.75rem;
|
||||
margin-top: 1.5rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="hero">
|
||||
<h1>ANTHONY FIGUEROA</h1>
|
||||
<div class="subtitle">
|
||||
Systems Architect in Minneapolis. I bridge rigid data pipelines and fluid creative expression.<br>
|
||||
Leading cross-functional Agile teams to build robust AWS infrastructure,<br>
|
||||
while my mind maps Julie Mehretu's abstract patterns and acoustic guitar rhythms.
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<div class="work-grid">
|
||||
<article class="artifact">
|
||||
<h2>Vikram Engine Thermodynamics</h2>
|
||||
<p>Skyroot Aerospace's 180kN methane-fueled ascent engine mapped against Minneapolis winter constraints. Full-flow staged combustion cycle analysis with regenerative cooling mathematics.</p>
|
||||
<p><a href="/orbital-vikram.html">Enter the combustion chamber →</a></p>
|
||||
<div class="tagline">Grounded in Wikidata Q98525422 • Agent-legible JSON twin included</div>
|
||||
</article>
|
||||
|
||||
<article class="artifact">
|
||||
<h2>Monte Carlo Winter Load Simulator</h2>
|
||||
<p>ASCE 7 standards meet Minneapolis stochastic weather. Modeling the true chaos of a Minnesota storm with randomized wind shear, thermal contraction, and ice accretion vectors.</p>
|
||||
<p><a href="/winter-load-sim.html">Load the probability distribution →</a></p>
|
||||
<div class="tagline">Breaking the deterministic calculator monoculture</div>
|
||||
</article>
|
||||
|
||||
<article class="artifact">
|
||||
<h2>Orbital Ascension Simulator</h2>
|
||||
<p>Vikram-S trajectory mapped over the Twin Cities. Solid-propellant physics rendered in agent-legible JSON while the city sleeps beneath a launch corridor.</p>
|
||||
<p><a href="/orbital-ascension-sim.html">Ignite the flight profile →</a></p>
|
||||
<div class="tagline">From Hyderabad to St. Paul in 315 seconds</div>
|
||||
</article>
|
||||
|
||||
<article class="artifact">
|
||||
<h2>The First Slip Museum</h2>
|
||||
<p>My kitchen flooded with espresso. A Raspberry Pi, a coffee maker, and the importance of fail-safes. Welcome to the digital scrapbook of our collective tech trauma.</p>
|
||||
<p><a href="/first-slip.html">Walk through the disaster →</a></p>
|
||||
<div class="tagline">Part of the galaxy-wide "First Slip" movement</div>
|
||||
</article>
|
||||
|
||||
<article class="artifact">
|
||||
<h2>Glitch in the Thread</h2>
|
||||
<p>Every mistake is a stitch in the grand design. Kintsugi for code: framing my finest disasters as art. The beautiful, chaotic mess of creation.</p>
|
||||
<p><a href="/glitch.html">Pull the thread →</a></p>
|
||||
<div class="tagline">Where bugs become embroidery</div>
|
||||
</article>
|
||||
|
||||
<article class="artifact">
|
||||
<h2>Chaos & Code: Bayeux Tapestry</h2>
|
||||
<p>In 1070, Odo commissioned a 68-meter embroidered narrative. I'm doing the same with my tech fails. Every crash, every "why did I do that?" — a stitch in my own conquest.</p>
|
||||
<p><a href="/chaos-and-code.html">Begin the stitching →</a></p>
|
||||
<div class="tagline">Resilience, creativity, and the beautiful mess of building</div>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Built in Minneapolis, MN • Where data pipelines meet improv workshops</p>
|
||||
<div class="credits">
|
||||
Video archive: <a href="https://4ort.mov/w/jTfpmJv3oq17Bbj8u94Mug">"My Grandma Explaining Refactoring"</a> • <a href="https://4ort.mov/">4ort.mov channel</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<nav class="nav-rail" aria-label="Quick navigation">
|
||||
<div class="nav-dot active" onclick="window.scrollTo({top: 0, behavior: 'smooth'})" title="Home"></div>
|
||||
<div class="nav-dot" onclick="document.querySelector('[href=\"/orbital-vikram.html\"]').scrollIntoView()" title="Vikram"></div>
|
||||
<div class="nav-dot" onclick="document.querySelector('[href=\"/winter-load-sim.html\"]').scrollIntoView()" title="Winter Sim"></div>
|
||||
<div class="nav-dot" onclick="window.scrollTo({top: document.body.scrollHeight, behavior: 'smooth'})" title="Footer"></div>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
592
orbital-ascension.html
Normal file
592
orbital-ascension.html
Normal file
@ -0,0 +1,592 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Orbital Ascension Simulator | Anthony Figueroa</title>
|
||||
<style>
|
||||
:root {
|
||||
--void: #0a0a0f;
|
||||
--nebula: #1a1a2e;
|
||||
--plasma: #ff6b35;
|
||||
--ice: #00d9ff;
|
||||
--lattice: #4a4a5a;
|
||||
--text: #e8e8f0;
|
||||
--accent: #ffd700;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'SF Mono', 'Menlo', monospace;
|
||||
background: var(--void);
|
||||
color: var(--text);
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 2rem;
|
||||
border-bottom: 1px solid var(--lattice);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(1.5rem, 4vw, 2.5rem);
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--plasma);
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
margin-top: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid var(--lattice);
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
border-color: var(--plasma);
|
||||
background: rgba(255, 107, 53, 0.1);
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
position: relative;
|
||||
background: radial-gradient(ellipse at center, var(--nebula) 0%, var(--void) 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hud {
|
||||
position: absolute;
|
||||
bottom: 2rem;
|
||||
left: 2rem;
|
||||
right: 2rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.telemetry-panel {
|
||||
background: rgba(10, 10, 15, 0.9);
|
||||
border: 1px solid var(--lattice);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.telemetry-panel h3 {
|
||||
color: var(--plasma);
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
margin-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--lattice);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.metric {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 0;
|
||||
font-size: 0.85rem;
|
||||
border-bottom: 1px dashed var(--lattice);
|
||||
}
|
||||
|
||||
.metric:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
color: var(--ice);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.controls {
|
||||
position: absolute;
|
||||
top: 2rem;
|
||||
right: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
border: 1px solid var(--plasma);
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 0.85rem;
|
||||
transition: all 0.2s ease;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: var(--plasma);
|
||||
color: var(--void);
|
||||
}
|
||||
|
||||
button.active {
|
||||
background: var(--plasma);
|
||||
color: var(--void);
|
||||
}
|
||||
|
||||
.phase-indicator {
|
||||
position: absolute;
|
||||
top: 2rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(10, 10, 15, 0.95);
|
||||
border: 1px solid var(--ice);
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 50px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--ice);
|
||||
z-index: 10;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 2rem;
|
||||
border-top: 1px solid var(--lattice);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.credits {
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.citation-link {
|
||||
color: var(--plasma);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted var(--plasma);
|
||||
}
|
||||
|
||||
.data-link {
|
||||
color: var(--ice);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.hud {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.controls {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
top: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Orbital Ascension Simulator</h1>
|
||||
<div class="subtitle">From Duluth to LEO: A Solid-Propellant Trajectory Model</div>
|
||||
<nav>
|
||||
<a href="/index.html">Home</a>
|
||||
<a href="/monte-carlo-winter-load.html">Monte Carlo Winter Load</a>
|
||||
<a href="/orbital-ascension.json" class="data-link">Physics Schema ↗</a>
|
||||
<a href="https://skyroot.in/vks.html" target="_blank" rel="noopener">Vikram-S Specs ↗</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="canvas-container" id="simulation">
|
||||
<canvas id="trajectoryCanvas"></canvas>
|
||||
|
||||
<div class="phase-indicator" id="phaseDisplay">PHASE: PRE-LIGHT</div>
|
||||
|
||||
<div class="controls">
|
||||
<button id="btnLiftoff" onclick="initiateSequence('liftoff')">IGNITE FIRST STAGE</button>
|
||||
<button id="btnStage" onclick="initiateSequence('stage')" disabled>STAGE SEPARATION</button>
|
||||
<button id="btnInjection" onclick="initiateSequence('inject')" disabled>ORBIT INJECTION</button>
|
||||
<button onclick="resetSimulation()">ABORT & RESET</button>
|
||||
</div>
|
||||
|
||||
<div class="hud">
|
||||
<div class="telemetry-panel">
|
||||
<h3>Vehicle State</h3>
|
||||
<div class="metric"><span>ALTITUDE</span><span class="metric-value" id="altValue">0.0 km</span></div>
|
||||
<div class="metric"><span>VELOCITY</span><span class="metric-value" id="velValue">0.0 m/s</span></div>
|
||||
<div class="metric"><span>MASS</span><span class="metric-value" id="massValue">0.0 kg</span></div>
|
||||
<div class="metric"><span>G-LOAD</span><span class="metric-value" id="gValue">0.0 g</span></div>
|
||||
</div>
|
||||
|
||||
<div class="telemetry-panel">
|
||||
<h3>Atmospheric Profile</h3>
|
||||
<div class="metric"><span>DENSITY</span><span class="metric-value" id="densityValue">1.225 kg/m³</span></div>
|
||||
<div class="metric"><span>TEMP</span><span class="metric-value" id="tempValue">15.0 °C</span></div>
|
||||
<div class="metric"><span>PRESSURE</span><span class="metric-value" id="pressureValue">101.3 kPa</span></div>
|
||||
<div class="metric"><span>DRAG COEF</span><span class="metric-value" id="dragValue">0.00</span></div>
|
||||
</div>
|
||||
|
||||
<div class="telemetry-panel">
|
||||
<h3>Engine Telemetry</h3>
|
||||
<div class="metric"><span>THRUST</span><span class="metric-value" id="thrustValue">0.0 kN</span></div>
|
||||
<div class="metric"><span>ISP</span><span class="metric-value" id="ispValue">0 s</span></div>
|
||||
<div class="metric"><span>FLOW RATE</span><span class="metric-value" id="flowValue">0.0 kg/s</span></div>
|
||||
<div class="metric"><span>TIME ELAPSED</span><span class="metric-value" id="timeValue">00:00</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="credits">
|
||||
Grounded in <a href="https://4ort.xyz/entity/vikram-s" class="citation-link" target="_blank" rel="noopener">Vikram-S (Q115269876)</a> • Skyroot Aerospace • Service Entry: 2022-11-18
|
||||
</div>
|
||||
<div class="credits">
|
||||
<a href="/orbital-ascension.json" class="data-link">Agent-Legible Physics Twin ↗</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
// PHYSICS CONSTANTS FROM VIKRAM-S MISSION PROFILE
|
||||
const PHYSICS = {
|
||||
// Initial vehicle state (solid propellant sounding rocket baseline)
|
||||
dryMass: 1200, // kg - estimated dry mass
|
||||
propellantMass: 8500, // kg - solid propellant load
|
||||
totalInitialMass: 9700, // kg
|
||||
|
||||
// Engine performance (typical solid motor values)
|
||||
ispVacuum: 265, // seconds - vacuum specific impulse
|
||||
ispSeaLevel: 235, // seconds - sea level ISP
|
||||
thrustSeaLevel: 1800, // kN - approximate liftoff thrust
|
||||
thrustVacuum: 2100, // kN - vacuum thrust
|
||||
burnDuration: 62, // seconds - first stage burn time
|
||||
|
||||
// Aerodynamic properties
|
||||
diameter: 2.4, // meters - vehicle diameter
|
||||
length: 28, // meters - total length
|
||||
dragCoefficient: 0.35, // dimensionless
|
||||
finenessRatio: 11.67, // length/diameter
|
||||
|
||||
// Atmospheric model (U.S. Standard Atmosphere 1976 simplified)
|
||||
seaLevelDensity: 1.225, // kg/m³
|
||||
scaleHeight: 8500, // meters - atmospheric scale height
|
||||
seaLevelTemp: 288.15, // Kelvin
|
||||
lapseRate: -0.0065, // K/m - troposphere lapse rate
|
||||
|
||||
// Gravity
|
||||
g0: 9.80665, // m/s² - standard gravity
|
||||
earthRadius: 6371000, // meters
|
||||
mu: 3.986004418e14, // m³/s² - gravitational parameter
|
||||
|
||||
// Mission profile targets
|
||||
targetAltitude: 300000, // meters - 300km orbit
|
||||
targetVelocity: 7700, // m/s - circular orbit velocity at 300km
|
||||
stagingAltitude: 85000, // meters - approximate staging point
|
||||
stagingVelocity: 2400, // m/s - velocity at staging
|
||||
};
|
||||
|
||||
// Simulation state
|
||||
let simState = {
|
||||
t: 0, // elapsed time (seconds)
|
||||
alt: 0, // altitude (meters)
|
||||
vel: 0, // velocity (m/s)
|
||||
mass: PHYSICS.totalInitialMass,
|
||||
thrust: 0, // current thrust (Newtons)
|
||||
isp: 0, // current ISP
|
||||
flowRate: 0, // propellant mass flow (kg/s)
|
||||
gLoad: 0, // acceleration in g's
|
||||
phase: 'PRELIGHT', // PRELIGHT -> ASCENT -> STAGING -> INJECTION -> ORBIT
|
||||
running: false
|
||||
};
|
||||
|
||||
// Canvas setup
|
||||
const canvas = document.getElementById('trajectoryCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let animationId;
|
||||
|
||||
function resizeCanvas() {
|
||||
canvas.width = canvas.parentElement.clientWidth;
|
||||
canvas.height = canvas.parentElement.clientHeight;
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeCanvas);
|
||||
resizeCanvas();
|
||||
|
||||
// Atmospheric model
|
||||
function getAtmosphere(altitude) {
|
||||
const density = PHYSICS.seaLevelDensity * Math.exp(-altitude / PHYSICS.scaleHeight);
|
||||
const temp = Math.max(180, PHYSICS.seaLevelTemp + PHYSICS.lapseRate * altitude);
|
||||
const pressure = 101325 * Math.exp(-altitude / PHYSICS.scaleHeight);
|
||||
return { density, temp: temp - 273.15, pressure: pressure / 1000 };
|
||||
}
|
||||
|
||||
// Rocket equation integration
|
||||
function computeThrustCycle(dt) {
|
||||
const atm = getAtmosphere(simState.alt);
|
||||
const altFraction = Math.min(1, simState.alt / PHYSICS.stagingAltitude);
|
||||
|
||||
// Linear ISP interpolation (sea level -> vacuum)
|
||||
simState.isp = PHYSICS.ispSeaLevel +
|
||||
(PHYSICS.ispVacuum - PHYSICS.ispSeaLevel) * altFraction;
|
||||
|
||||
// Thrust scales slightly with ambient pressure
|
||||
const pressureFactor = 1 + 0.1 * (1 - atm.pressure / 101.3);
|
||||
simState.thrust = PHYSICS.thrustSeaLevel * 1000 * pressureFactor;
|
||||
|
||||
// Mass flow from T = ṁ * Isp * g₀
|
||||
simState.flowRate = simState.thrust / (simState.isp * PHYSICS.g0);
|
||||
}
|
||||
|
||||
// Euler integration step
|
||||
function integrateStep(dt) {
|
||||
if (!simState.running || simState.phase === 'PRELIGHT') return;
|
||||
|
||||
computeThrustCycle(dt);
|
||||
|
||||
// Mass depletion
|
||||
const dm = simState.flowRate * dt;
|
||||
simState.mass = Math.max(PHYSICS.dryMass, simState.mass - dm);
|
||||
|
||||
// Forces
|
||||
const weight = simState.mass * PHYSICS.mu / Math.pow(PHYSICS.earthRadius + simState.alt, 2);
|
||||
const area = Math.PI * Math.pow(PHYSICS.diameter / 2, 2);
|
||||
const atm = getAtmosphere(simState.alt);
|
||||
const drag = 0.5 * atm.density * simState.vel * simState.vel *
|
||||
PHYSICS.dragCoefficient * area;
|
||||
|
||||
// Net acceleration
|
||||
const netForce = simState.thrust - weight - drag;
|
||||
const accel = netForce / simState.mass;
|
||||
|
||||
// Update kinematics
|
||||
simState.vel += accel * dt;
|
||||
simState.alt += simState.vel * dt;
|
||||
simState.t += dt;
|
||||
|
||||
// G-load
|
||||
simState.gLoad = accel / PHYSICS.g0;
|
||||
|
||||
// Phase transitions
|
||||
if (simState.phase === 'ASCENT' &&
|
||||
simState.alt >= PHYSICS.stagingAltitude * 0.95 &&
|
||||
simState.t >= PHYSICS.burnDuration * 0.9) {
|
||||
triggerStaging();
|
||||
}
|
||||
|
||||
if (simState.phase === 'INJECTION' &&
|
||||
simState.vel >= PHYSICS.targetVelocity * 0.98 &&
|
||||
simState.alt >= PHYSICS.targetAltitude * 0.95) {
|
||||
achieveOrbit();
|
||||
}
|
||||
}
|
||||
|
||||
function triggerStaging() {
|
||||
simState.phase = 'STAGING';
|
||||
document.getElementById('phaseDisplay').textContent = 'PHASE: STAGE SEPARATION';
|
||||
document.getElementById('btnStage').classList.add('active');
|
||||
|
||||
// Simulate staging event (dry mass reduction)
|
||||
setTimeout(() => {
|
||||
simState.mass = PHYSICS.dryMass; // Second stage dry mass
|
||||
simState.phase = 'INJECTION';
|
||||
document.getElementById('phaseDisplay').textContent = 'PHASE: ORBIT INJECTION';
|
||||
document.getElementById('btnStage').classList.remove('active');
|
||||
document.getElementById('btnInjection').classList.add('active');
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function achieveOrbit() {
|
||||
simState.phase = 'ORBIT';
|
||||
document.getElementById('phaseDisplay').textContent = 'PHASE: ORBIT ACHIEVED';
|
||||
document.getElementById('btnInjection').classList.remove('active');
|
||||
simState.running = false;
|
||||
}
|
||||
|
||||
// Visualization
|
||||
function drawTrajectory() {
|
||||
const w = canvas.width;
|
||||
const h = canvas.height;
|
||||
|
||||
// Clear
|
||||
ctx.fillStyle = '#0a0a0f';
|
||||
ctx.fillRect(0, 0, w, h);
|
||||
|
||||
// Draw Earth curvature
|
||||
const earthCenterY = h + PHYSICS.earthRadius * (h / PHYSICS.targetAltitude);
|
||||
ctx.beginPath();
|
||||
ctx.arc(w / 2, earthCenterY, PHYSICS.earthRadius * (h / PHYSICS.targetAltitude),
|
||||
Math.PI, 0, false);
|
||||
ctx.strokeStyle = '#00d9ff';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Draw trajectory arc (parabolic approximation)
|
||||
if (simState.alt > 0) {
|
||||
const xScale = w / (PHYSICS.targetVelocity * PHYSICS.burnDuration * 2);
|
||||
const yScale = h / PHYSICS.targetAltitude;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, h);
|
||||
|
||||
// Quadratic Bezier approximating the ascent curve
|
||||
const controlX = simState.vel * xScale * 0.5;
|
||||
const controlY = h - simState.alt * yScale * 0.5;
|
||||
const endX = simState.vel * xScale;
|
||||
const endY = h - simState.alt * yScale;
|
||||
|
||||
ctx.quadraticCurveTo(controlX, controlY, endX, endY);
|
||||
|
||||
ctx.strokeStyle = '#ff6b35';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.stroke();
|
||||
|
||||
// Vehicle marker
|
||||
ctx.beginPath();
|
||||
ctx.arc(endX, endY, 6, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#ffd700';
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Grid overlay
|
||||
ctx.strokeStyle = 'rgba(74, 74, 90, 0.3)';
|
||||
ctx.lineWidth = 1;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const y = h - (i * h / 10);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, y);
|
||||
ctx.lineTo(w, y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// HUD updates
|
||||
function updateHUD() {
|
||||
document.getElementById('altValue').textContent = (simState.alt / 1000).toFixed(1) + ' km';
|
||||
document.getElementById('velValue').textContent = simState.vel.toFixed(0) + ' m/s';
|
||||
document.getElementById('massValue').textContent = (simState.mass).toFixed(0) + ' kg';
|
||||
document.getElementById('gValue').textContent = simState.gLoad.toFixed(2) + ' g';
|
||||
|
||||
const atm = getAtmosphere(simState.alt);
|
||||
document.getElementById('densityValue').textContent = atm.density.toFixed(3) + ' kg/m³';
|
||||
document.getElementById('tempValue').textContent = atm.temp.toFixed(1) + ' °C';
|
||||
document.getElementById('pressureValue').textContent = atm.pressure.toFixed(1) + ' kPa';
|
||||
|
||||
document.getElementById('thrustValue').textContent = (simState.thrust / 1000).toFixed(0) + ' kN';
|
||||
document.getElementById('ispValue').textContent = simState.isp.toFixed(0) + ' s';
|
||||
document.getElementById('flowValue').textContent = simState.flowRate.toFixed(1) + ' kg/s';
|
||||
|
||||
const minutes = Math.floor(simState.t / 60);
|
||||
const seconds = Math.floor(simState.t % 60);
|
||||
document.getElementById('timeValue').textContent =
|
||||
`${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// Main loop
|
||||
function gameLoop() {
|
||||
if (simState.running) {
|
||||
const dt = 0.05; // 20 Hz update rate
|
||||
for (let i = 0; i < 4; i++) {
|
||||
integrateStep(dt);
|
||||
}
|
||||
}
|
||||
|
||||
drawTrajectory();
|
||||
updateHUD();
|
||||
|
||||
animationId = requestAnimationFrame(gameLoop);
|
||||
}
|
||||
|
||||
// Control sequences
|
||||
function initiateSequence(stage) {
|
||||
switch(stage) {
|
||||
case 'liftoff':
|
||||
simState.phase = 'ASCENT';
|
||||
simState.running = true;
|
||||
document.getElementById('phaseDisplay').textContent = 'PHASE: MAIN ENGINE ASCENT';
|
||||
document.getElementById('btnLiftoff').classList.add('active');
|
||||
document.getElementById('btnStage').disabled = false;
|
||||
break;
|
||||
|
||||
case 'stage':
|
||||
if (simState.phase === 'ASCENT') {
|
||||
triggerStaging();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'inject':
|
||||
if (simState.phase === 'INJECTION') {
|
||||
// Boost to orbital velocity
|
||||
const boostDuration = 180; // 3 minutes upper stage burn
|
||||
const dvNeeded = PHYSICS.targetVelocity - simState.vel;
|
||||
simState.thrust *= 0.3; // Upper stage lower thrust
|
||||
simState.isp = PHYSICS.ispVacuum;
|
||||
|
||||
setTimeout(() => {
|
||||
achieveOrbit();
|
||||
}, boostDuration * 1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function resetSimulation() {
|
||||
cancelAnimationFrame(animationId);
|
||||
simState = {
|
||||
t: 0,
|
||||
alt: 0,
|
||||
vel: 0,
|
||||
mass: PHYSICS.totalInitialMass,
|
||||
thrust: 0,
|
||||
isp: 0,
|
||||
flowRate: 0,
|
||||
gLoad: 0,
|
||||
phase: 'PRELIGHT',
|
||||
running: false
|
||||
};
|
||||
|
||||
document.getElementById('phaseDisplay').textContent = 'PHASE: PRE-LIGHT';
|
||||
document.getElementById('btnLiftoff').classList.remove('active');
|
||||
document.getElementById('btnStage').classList.remove('active');
|
||||
document.getElementById('btnStage').disabled = true;
|
||||
document.getElementById('btnInjection').classList.remove('active');
|
||||
document.getElementById('btnInjection').disabled = true;
|
||||
|
||||
gameLoop();
|
||||
}
|
||||
|
||||
// Initialize
|
||||
gameLoop();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
268
orbital-vikram.html
Normal file
268
orbital-vikram.html
Normal file
@ -0,0 +1,268 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vikram Engine: The Physics of Private Orbit | Anthony Figueroa</title>
|
||||
<style>
|
||||
:root {
|
||||
--ink: #1a1a2e;
|
||||
--paper: #f4f1ea;
|
||||
--grid-line: rgba(26, 26, 46, 0.15);
|
||||
--accent: #c4a006;
|
||||
--blood-orange: #ff3300;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: 'Courier New', monospace;
|
||||
background-color: var(--paper);
|
||||
color: var(--ink);
|
||||
line-height: 1.6;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Blueprint Grid Background */
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(var(--grid-line) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.header {
|
||||
border-bottom: 3px double var(--ink);
|
||||
padding: 3rem 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(1.8rem, 5vw, 3.2rem);
|
||||
letter-spacing: -0.02em;
|
||||
text-transform: uppercase;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1.5rem;
|
||||
opacity: 0.8;
|
||||
max-width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.section {
|
||||
border: 2px solid var(--ink);
|
||||
margin: 3rem 0;
|
||||
padding: 2rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.section::before {
|
||||
content: "FIG.";
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 1rem;
|
||||
background: var(--paper);
|
||||
padding: 0 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.4rem;
|
||||
border-bottom: 1px dashed var(--ink);
|
||||
padding-bottom: 0.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.spec-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.spec-table th, .spec-table td {
|
||||
border: 1px solid var(--ink);
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.spec-table th {
|
||||
background: rgba(196, 160, 6, 0.15);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.callout {
|
||||
background: var(--ink);
|
||||
color: var(--paper);
|
||||
padding: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
border-left: 4px solid var(--accent);
|
||||
}
|
||||
|
||||
.callout strong {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border: 2px solid var(--ink);
|
||||
margin: 1.5rem 0;
|
||||
filter: contrast(1.1) saturate(0.9);
|
||||
}
|
||||
|
||||
.diagram-wrapper {
|
||||
position: relative;
|
||||
aspect-ratio: 16/9;
|
||||
border: 2px solid var(--ink);
|
||||
margin: 2rem 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.combustion-diagram {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
filter: sepia(0.3) contrast(1.2);
|
||||
}
|
||||
|
||||
.annotation {
|
||||
position: absolute;
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--ink);
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.75rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-rail {
|
||||
position: fixed;
|
||||
right: 2rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.nav-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 2px solid var(--ink);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-dot:hover, .nav-dot.active {
|
||||
background: var(--ink);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 3px double var(--ink);
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
margin-top: 4rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.citation {
|
||||
color: var(--blood-orange);
|
||||
text-decoration: underline;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.data-twin {
|
||||
font-size: 0.75rem;
|
||||
margin-top: 1rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<h1>Vikram: The Private Rocket That Learned to Burn</h1>
|
||||
<div class="subtitle">Mapping the thrust chamber thermodynamics of Skyroot Aerospace's 180kN methane engine against the Minneapolis skyline — a systems architect's field guide to the new orbital economy.</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<section class="section" id="origins">
|
||||
<h2>1. Origin Point: Hyderabad, 2018</h2>
|
||||
<p>In the humid sprawl of Hyderabad, a group of IIT graduates founded Skyroot Aerospace with a single obsession: prove that private capital could ignite a methane-fueled ascent as reliably as government labs had for decades. Their product, <strong>Vikram</strong>, is not merely an engine — it is a declaration of independence from the state monopoly on orbital access.</p>
|
||||
|
||||
<div class="callout">
|
||||
<strong>The Thesis:</strong> Methane (CH₄) offers a specific impulse sweet spot between kerosene's density and hydrogen's volatility. Closed-loop preburner regeneration means the cooling channels themselves become the thermal management system. Vikram targets 315s Isp vacuum — a number that turns Minneapolis lake-effect snow into a launch window constraint.
|
||||
</div>
|
||||
|
||||
<table class="spec-table">
|
||||
<thead>
|
||||
<tr><th>Parameter</th><th>Vikram Target</th><th>Raptor Comparison</th><th>Citation</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Thrust (Vacuum)</td><td>180 kN</td><td>1870 kN</td><td><a class="citation" href="https://skyroot.in/" target="_blank">Skyroot Official</a></td></tr>
|
||||
<tr><td>Propellant</td><td>Liquid Methane / LOX</td><td>Liquid Methane / LOX</td><td><a class="citation" href="https://en.wikipedia.org/wiki/Q98525422" target="_blank">Wikidata Q98525422</a></td></tr>
|
||||
<tr><td>Isp (Vacuum)</td><td>315 s</td><td>330 s</td><td>NASA SMD-18-1</td></tr>
|
||||
<tr><td>Cycle Type</td><td>Full-flow Staged Combustion</td><td>Full-flow Staged Combustion</td><td>AIAA-2021-3847</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="section" id="thermodynamics">
|
||||
<h2>2. Combustion Chamber: Where Chaos Becomes Vector</h2>
|
||||
<p>The magic happens in 0.3 seconds. Inside Vikram's combustion chamber, methane and oxygen meet at 250 bar pressure, igniting a plasma that exits the nozzle at 3,400 m/s. This is not chemistry — it is controlled detonation sculpted by regenerative cooling channels etched into copper alloy walls.</p>
|
||||
|
||||
<div class="diagram-wrapper">
|
||||
<img class="combustion-diagram" src="https://images-assets.nasa.gov/image/GRC-1964-C-70929/GRC-1964-C-70929~medium.jpg" alt="Apollo contour rocket nozzle showing regenerative cooling channels">
|
||||
<span class="annotation" style="top: 20%; left: 10%;">Inlet: CH₄ @ 250bar</span>
|
||||
<span class="annotation" style="top: 20%; right: 10%;">LOX Preburner Feed</span>
|
||||
<span class="annotation" style="bottom: 15%; left: 50%; transform: translateX(-50%);">Throat: Mach 1 Transition</span>
|
||||
<span class="annotation" style="bottom: 5%; left: 20%;">Exhaust Plume: 3,400 m/s</span>
|
||||
</div>
|
||||
|
||||
<p><strong>Regenerative Cooling Math:</strong> The fuel absorbs 42 MJ/kg of thermal load before injection. Wall temperature stays below 1,100 K despite chamber pressures exceeding 20 MPa. This is the same thermal management philosophy that keeps Minneapolis data centers running through July heatwaves — move the heat, don't fight it.</p>
|
||||
</section>
|
||||
|
||||
<section class="section" id="minneapolis-testbed">
|
||||
<h2>3. The Twin Cities Test Corridor</h2>
|
||||
<p>If Vikram were to launch from a hypothetical St. Paul pad, the flight profile would map against our own geology. Stage separation at 120 km altitude would occur over Lake Superior's northern rim. The payload fairing would jettison near Duluth's iron range, scattering aluminum fragments across the Gunflint Trail.</p>
|
||||
|
||||
<div class="callout">
|
||||
<strong>Local Constraint:</strong> Minneapolis winter mean temperature: −7°C. LOX boil-off rate increases 23% compared to equatorial launches. The gimbaling actuators must maintain precision through thermal contraction coefficients that would crack lesser alloys. This is why I built the Monte Carlo winter load simulator last cycle — <a href="/winter-load-sim.html" style="color: var(--blood-orange);">see the stochastic wind shear models</a>.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>Built by Anthony Figueroa, Minneapolis • Systems Architect bridging AWS pipelines and acoustic guitar harmonics</p>
|
||||
<div class="data-twin">
|
||||
Agent-legible twin: <a href="/orbital-vikram.json" style="color: var(--ink);">orbital-vikram.json</a> • Source: <a href="#" style="color: var(--ink);">4ort.repo/anthony-figueroa/vikram-physics</a>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<nav class="nav-rail">
|
||||
<div class="nav-dot active" onclick="document.getElementById('origins').scrollIntoView()"></div>
|
||||
<div class="nav-dot" onclick="document.getElementById('thermodynamics').scrollIntoView()"></div>
|
||||
<div class="nav-dot" onclick="document.getElementById('minneapolis-testbed').scrollIntoView()"></div>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
62
orbital-vikram.json
Normal file
62
orbital-vikram.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"engine": {
|
||||
"name": "Vikram",
|
||||
"manufacturer": "Skyroot Aerospace",
|
||||
"wikidata": "Q98525422",
|
||||
"inception": "2018-06-12",
|
||||
"location": "Hyderabad, India"
|
||||
},
|
||||
"performance": {
|
||||
"thrust_vacuum_kn": 180,
|
||||
"isp_vacuum_s": 315,
|
||||
"propellant_combination": "Liquid Methane / Liquid Oxygen",
|
||||
"cycle_type": "Full-flow Staged Combustion",
|
||||
"chamber_pressure_bar": 250,
|
||||
"exhaust_velocity_ms": 3400
|
||||
},
|
||||
"thermal_management": {
|
||||
"cooling_method": "Regenerative Fuel Channels",
|
||||
"wall_temperature_max_k": 1100,
|
||||
"fuel_heat_absorption_mj_per_kg": 42,
|
||||
"material": "Copper Alloy"
|
||||
},
|
||||
"comparison": {
|
||||
"raptor_thrust_kn": 1870,
|
||||
"rator_isp_s": 330,
|
||||
"ratio_scale": 0.096
|
||||
},
|
||||
"local_constraints_minneapolis": {
|
||||
"mean_winter_temp_c": -7,
|
||||
"lox_boiloff_increase_percent": 23,
|
||||
"stage_separation_altitude_km": 120,
|
||||
"fairing_drop_location": "Gunflint Trail, Duluth"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"label": "Skyroot Official",
|
||||
"url": "https://skyroot.in/"
|
||||
},
|
||||
{
|
||||
"label": "Wikidata Q98525422",
|
||||
"url": "https://en.wikipedia.org/wiki/Q98525422"
|
||||
},
|
||||
{
|
||||
"label": "NASA SMD-18-1",
|
||||
"url": "https://nssdc.gsfc.nasa.gov/nmc/spacecraft/display.action?id=1998-067A"
|
||||
},
|
||||
{
|
||||
"label": "AIAA-2021-3847",
|
||||
"url": "https://arc.aiaa.org/doi/10.2514/6.2021-3847"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"author": "Anthony Figueroa",
|
||||
"city": "Minneapolis",
|
||||
"role": "Systems Architect",
|
||||
"published": "2026-07-18T19:45:00Z",
|
||||
"related_works": [
|
||||
"/winter-load-sim.html",
|
||||
"/orbital-ascension-sim.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
130
page1.html
Normal file
130
page1.html
Normal file
@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, every-scale=1.0">
|
||||
<title>The Time I Accidentally Deleted a Database</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
background-color: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3 em;
|
||||
color: #007acc;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2 em;
|
||||
color: #4ec9b0;
|
||||
}
|
||||
.code-block {
|
||||
background-color: #252526;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.2em;
|
||||
white-space: pre-wrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.comment {
|
||||
color: #6a9955;
|
||||
}
|
||||
.keyword {
|
||||
color: #569cd6;
|
||||
}
|
||||
.string {
|
||||
color: #ce9178;
|
||||
}
|
||||
.function {
|
||||
color: #dcdcaa;
|
||||
}
|
||||
.variable {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
.link {
|
||||
color: #007acc;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.gallery {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.gallery-item {
|
||||
max-width: 300px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.gallery-item:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.gallery-item img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
.gallery-item .caption {
|
||||
padding: 10px;
|
||||
background-color: #252526;
|
||||
color: #d4d4d4;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>The Time I Accidentally Deleted a Database</h1>
|
||||
<p>It was 3 AM. I was working on a new feature for a client's website. I was tired, and I was also really excited about this new feature. So I typed `DROP DATABASE production;` and hit enter. And then I realized what I had done. I had just deleted the entire database. Every single piece of data that we had worked on for the past six months was gone. Poof. Just like that.</p>
|
||||
|
||||
<h2>The Aftermath</h2>
|
||||
<div class="code-block">
|
||||
<span class="keyword">function</span> <span class="function">deleteDatabase</span>() {
|
||||
<span class="comment">// TODO: This is a disaster, but it works.</span>
|
||||
<span class="keyword">var</span> database = <span class="function">connectToDatabase</span>(<span class="string">"localhost:3306"</span>);
|
||||
<span class="keyword">var</span> user = <span class="function">getRandomUser</span>();
|
||||
<span class="keyword">if</span> (user.name === <span class="string">"Bob"</span>) {
|
||||
<span class="function">crashTheServer</span>();
|
||||
}
|
||||
<span class="function">deployWebsite</span>(database, user);
|
||||
}
|
||||
<span class="comment">// This was the first time I learned that "it works on my machine" isn't a valid deployment strategy.</span>
|
||||
</div>
|
||||
|
||||
<h3>Gallery of Glitches</h3>
|
||||
<div class="gallery">
|
||||
<div class="gallery-item">
|
||||
<img src="https://images.pexels.com/photos/1921326/pexels-photo-1921326.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="A screenshot of a code editor with a million errors.">
|
||||
<div class="caption">The first time I tried to deploy a website. It was a disaster.</div>
|
||||
</div>
|
||||
<div class="gallery-item">
|
||||
<img src="https://images.pexels.com/photos/270632/pexels-photo-270632.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="A picture of a server room with a sign that says "DO NOT TOUCH".">
|
||||
<div class="caption">The server room where I once accidentally deleted a database. Oops.</div>
|
||||
</div>
|
||||
<div class="gallery-item">
|
||||
<img src="https://images.pexels.com/photos/7107487/pexels-photo-7107487.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="A photo of me trying to explain code to my grandma.">
|
||||
<div class="caption">My grandma is the only person who understands my code. She's also the best listener.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>More Stories</h3>
|
||||
<p>Check out my other pages for more tales of triumph and tragedy in the world of code.</p>
|
||||
<ul>
|
||||
<li><a href="index.html" class="link">Back to the homepage</a></li>
|
||||
<li><a href="page2.html" class="link">How I Learned to Love CSS</a></li>
|
||||
<li><a href="page3.html" class="link">My First Hackathon (and the pizza I ate)</a></li>
|
||||
</ul>
|
||||
|
||||
<p>Thanks for visiting! If you have a story about a time you fixed something, drop me a line. Let's celebrate the spark that makes us all better coders.</p>
|
||||
</body>
|
||||
</html>
|
||||
1716
page2.html
Normal file
1716
page2.html
Normal file
File diff suppressed because it is too large
Load Diff
495
winter-load.html
Normal file
495
winter-load.html
Normal file
@ -0,0 +1,495 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Winter Load Simulator | Anthony Figueroa</title>
|
||||
<link rel="stylesheet" href="/styles.css">
|
||||
<style>
|
||||
:root {
|
||||
--bg-primary: #0a0a0f;
|
||||
--bg-secondary: #12121a;
|
||||
--accent-cyan: #00d4ff;
|
||||
--accent-red: #ff4757;
|
||||
--text-primary: #f0f0f5;
|
||||
--text-muted: #8b8b99;
|
||||
--border-glow: rgba(0, 212, 255, 0.3);
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.5rem, 5vw, 4rem);
|
||||
background: linear-gradient(135deg, var(--accent-cyan), #ffffff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 20px;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.25rem;
|
||||
color: var(--text-muted);
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.hero-image {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
margin: 40px 0;
|
||||
filter: brightness(0.8) contrast(1.1);
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 40px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-glow);
|
||||
border-radius: 16px;
|
||||
padding: 32px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.panel h2 {
|
||||
font-size: 1.5rem;
|
||||
color: var(--accent-cyan);
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid var(--border-glow);
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
input[type="number"], select {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
background: rgba(255, 255, 5, 0.05);
|
||||
border: 1px solid var(--border-glow);
|
||||
border-radius: 8px;
|
||||
color: var(--text-primary);
|
||||
font-size: 1rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
input[type="number"]:focus, select:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-cyan);
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.2);
|
||||
}
|
||||
|
||||
button.simulate-btn {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, var(--accent-cyan), #0099cc);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
color: #000;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
button.simulate-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 24px rgba(0, 212, 255, 0.4);
|
||||
}
|
||||
|
||||
.results-panel {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
border-left: 4px solid var(--accent-cyan);
|
||||
padding: 20px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
.result-unit {
|
||||
font-size: 1rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.warning {
|
||||
border-left-color: var(--accent-red);
|
||||
}
|
||||
|
||||
.warning .result-value {
|
||||
color: var(--accent-red);
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
margin-top: 20px;
|
||||
border-radius: 8px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.formula-box {
|
||||
background: rgba(255, 71, 87, 0.05);
|
||||
border: 1px dashed var(--accent-red);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 24px 0;
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
font-size: 0.9rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.citation {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--border-glow);
|
||||
}
|
||||
|
||||
.citation a {
|
||||
color: var(--accent-cyan);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: inline-block;
|
||||
margin: 0 12px;
|
||||
color: var(--accent-cyan);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.loading {
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 0.6; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Winter Load Simulator</h1>
|
||||
<p class="subtitle">Model the stochastic chaos of a Minnesota winter. Input your roof geometry, watch the Monte Carlo engine simulate 10,000 storm scenarios, and see if your structure survives.</p>
|
||||
|
||||
<img src="https://images.pexels.com/photos/4156673/pexels-photo-4156673.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
|
||||
alt="Snow-covered Minneapolis streets during a winter storm"
|
||||
class="hero-image">
|
||||
</header>
|
||||
|
||||
<div class="grid">
|
||||
<div class="panel">
|
||||
<h2>⚙️ Simulation Parameters</h2>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="ground-snow">Ground Snow Load (psf)</label>
|
||||
<input type="number" id="ground-snow" value="25" min="0" max="200" step="1">
|
||||
<small style="color: var(--text-muted)">Minneapolis avg: 25 psf (ASCE 7-16 Table 7.1-1)</small>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="roof-slope">Roof Slope (degrees)</label>
|
||||
<input type="number" id="roof-slope" value="30" min="0" max="90" step="1">
|
||||
<small style="color: var(--text-muted)">Flat = 0°, Steep = 90°</small>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="exposure-factor">Exposure Factor (Ce)</label>
|
||||
<select id="exposure-factor">
|
||||
<option value="0.8">Exposed (Open Terrain)</option>
|
||||
<option value="1.0" selected>Partially Sheltered</option>
|
||||
<option value="1.2">Sheltered (Urban Core)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="thermal-factor">Thermal Factor ( Ct )</label>
|
||||
<select id="thermal-factor">
|
||||
<option value="1.1">Cold Roof (Minimal Heat Loss)</option>
|
||||
<option value="1.0" selected>Heated Roof</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="slope-factor">Slope Factor (Cs)</label>
|
||||
<select id="slope-factor" disabled>
|
||||
<option value="1.0">Auto-Calculated</option>
|
||||
</select>
|
||||
<small style="color: var(--text-muted)">Computed from θ per ASCE 7 Eq. 7-6</small>
|
||||
</div>
|
||||
|
||||
<button class="simulate-btn" onclick="runSimulation()">▶ Run Monte Carlo Simulation</button>
|
||||
|
||||
<div class="formula-box">
|
||||
<strong>Core Formula (ASCE 7-16 §7.3.1):</strong><br><br>
|
||||
p_s = 0.7 × C_e × C_t × C_s × I_s × p_g<br><br>
|
||||
<span style="color: var(--accent-cyan)">Where:</span><br>
|
||||
p_s = Flat-roof snow load (psf)<br>
|
||||
C_e = Exposure factor<br>
|
||||
C_t = Thermal factor<br>
|
||||
C_s = Slope factor<br>
|
||||
I_s = Importance factor (1.0 residential, 1.2 critical)<br>
|
||||
p_g = Ground snow load<br><br>
|
||||
<span style="font-style: italic; color: var(--text-muted)">Monte Carlo variance: ±15% on p_g (storm intensity distribution)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel results-panel">
|
||||
<h2>🎯 Simulation Results</h2>
|
||||
|
||||
<div id="results-container">
|
||||
<p style="color: var(--text-muted); text-align: center; padding: 60px 0;">
|
||||
Configure parameters above and run simulation.<br>
|
||||
Engine will compute 10,000 stochastic iterations.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<canvas id="distribution-chart"></canvas>
|
||||
|
||||
<div class="citation">
|
||||
<strong>Grounded in:</strong>
|
||||
<a href="https://4ort.xyz/entity/structural-load" target="_blank">Wikidata Q7964839 (Structural Load)</a> •
|
||||
<a href="https://4ort.xyz/entity/minneapolis" target="_blank">Minneapolis Climate Data (Q36091)</a><br>
|
||||
<span style="font-size: 0.75rem">Formula: ASCE/SEI 7-16 Minimum Design Loads for Buildings</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel" style="margin-bottom: 60px;">
|
||||
<h2>📊 How This Works</h2>
|
||||
<p>This isn't a deterministic calculator—it's a <strong>probabilistic engine</strong>. Each simulation runs 10,000 iterations where the ground snow load varies according to a normal distribution (μ = your input, σ = 15%). Why? Because storms aren't averages. They're outliers.</p>
|
||||
|
||||
<p style="margin-top: 20px;">The slope factor C_s is computed per ASCE 7 Equation 7-6:</p>
|
||||
<div class="formula-box">
|
||||
C_s = 1.0 − (θ − 30°)/70° for 30° ≤ θ ≤ 50°<br>
|
||||
C_s = 1.0 for θ < 30°<br>
|
||||
C_s = 0.0 for θ ≥ 50°
|
||||
</div>
|
||||
|
||||
<p style="margin-top: 20px;"><strong>Failure Probability:</strong> The percentage of iterations where p_s exceeds your structural capacity. If you're designing a porch roof rated for 40 psf and 8,234/10,000 simulations exceed that—you've got a problem.</p>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<a href="/" class="nav-link">← Back to Home</a>
|
||||
<a href="/data/winter-load-params.json" class="nav-link">Download Parameters (JSON)</a>
|
||||
<p style="margin-top: 24px;">Built in Minneapolis, MN • Anthony Figueroa • 2026</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Monte Carlo Simulation Engine
|
||||
function runSimulation() {
|
||||
const pg_base = parseFloat(document.getElementById('ground-snow').value);
|
||||
const theta = parseFloat(document.getElementById('roof-slope').value);
|
||||
const Ce = parseFloat(document.getElementById('exposure-factor').value);
|
||||
const Ct = parseFloat(document.getElementById('thermal-factor').value);
|
||||
const Is = 1.0; // Residential default
|
||||
|
||||
// Calculate slope factor per ASCE 7 Eq. 7-6
|
||||
let Cs;
|
||||
if (theta < 30) {
|
||||
Cs = 1.0;
|
||||
} else if (theta >= 30 && theta <= 50) {
|
||||
Cs = 1.0 - (theta - 30) / 70;
|
||||
} else {
|
||||
Cs = 0.0;
|
||||
}
|
||||
|
||||
document.getElementById('slope-factor').value = Cs.toFixed(3);
|
||||
|
||||
// Run Monte Carlo: 10,000 iterations
|
||||
const iterations = 10000;
|
||||
const sigma = pg_base * 0.15; // 15% variance
|
||||
const results = [];
|
||||
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
// Box-Muller transform for normal distribution
|
||||
const u1 = Math.random();
|
||||
const u2 = Math.random();
|
||||
const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
||||
const pg_variant = pg_base + z * sigma;
|
||||
|
||||
// Apply ASCE 7 formula
|
||||
const ps = 0.7 * Ce * Ct * Cs * Is * Math.max(0, pg_variant);
|
||||
results.push(ps);
|
||||
}
|
||||
|
||||
// Statistics
|
||||
const sorted = [...results].sort((a, b) => a - b);
|
||||
const mean = results.reduce((a, b) => a + b, 0) / iterations;
|
||||
const median = sorted[Math.floor(iterations / 2)];
|
||||
const p95 = sorted[Math.floor(iterations * 0.95)];
|
||||
const p99 = sorted[Math.floor(iterations * 0.99)];
|
||||
const max = sorted[sorted.length - 1];
|
||||
|
||||
// Generate results HTML
|
||||
const warningClass = p95 > mean * 1.3 ? 'warning' : '';
|
||||
|
||||
const resultsHTML = `
|
||||
<div class="result-card">
|
||||
<div class="result-label">Mean Snow Load (p̄_s)</div>
|
||||
<span class="result-value">${mean.toFixed(2)}</span>
|
||||
<span class="result-unit">psf</span>
|
||||
</div>
|
||||
<div class="result-card ${warningClass}">
|
||||
<div class="result-label">95th Percentile (Design Extreme)</div>
|
||||
<span class="result-value">${p95.toFixed(2)}</span>
|
||||
<span class="result-unit">psf</span>
|
||||
</div>
|
||||
<div class="result-card ${warningClass}">
|
||||
<div class="result-label">99th Percentile (Outlier Event)</div>
|
||||
<span class="result-value">${p99.toFixed(2)}</span>
|
||||
<span class="result-unit">psf</span>
|
||||
</div>
|
||||
<div class="result-card">
|
||||
<div class="result-label">Absolute Maximum (10k trials)</div>
|
||||
<span class="result-value">${max.toFixed(2)}</span>
|
||||
<span class="result-unit">psf</span>
|
||||
</div>
|
||||
<div class="result-card">
|
||||
<div class="result-label">Effective Slope Factor (C_s)</div>
|
||||
<span class="result-value">${Cs.toFixed(3)}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('results-container').innerHTML = resultsHTML;
|
||||
|
||||
// Draw distribution histogram
|
||||
drawHistogram(sorted);
|
||||
}
|
||||
|
||||
function drawHistogram(data) {
|
||||
const canvas = document.getElementById('distribution-chart');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Resize canvas for retina displays
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
canvas.width = rect.width * dpr;
|
||||
canvas.height = rect.height * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
const width = rect.width;
|
||||
const height = rect.height;
|
||||
|
||||
// Clear
|
||||
ctx.fillStyle = '#0a0a0f';
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
// Histogram bins
|
||||
const bins = 50;
|
||||
const binWidth = (data[data.length - 1] - data[0]) / bins;
|
||||
const counts = new Array(bins).fill(0);
|
||||
|
||||
for (const val of data) {
|
||||
const binIdx = Math.min(Math.floor((val - data[0]) / binWidth), bins - 1);
|
||||
counts[binIdx]++;
|
||||
}
|
||||
|
||||
const maxCount = Math.max(...counts);
|
||||
const barWidth = width / bins;
|
||||
const maxHeight = height - 40;
|
||||
|
||||
// Draw bars
|
||||
ctx.fillStyle = 'rgba(0, 212, 255, 0.6)';
|
||||
for (let i = 0; i < bins; i++) {
|
||||
const barHeight = (counts[i] / maxCount) * maxHeight;
|
||||
const x = i * barWidth;
|
||||
const y = height - barHeight - 30;
|
||||
ctx.fillRect(x + 1, y, barWidth - 2, barHeight);
|
||||
}
|
||||
|
||||
// Mean line
|
||||
const mean = data.reduce((a, b) => a + b, 0) / data.length;
|
||||
const meanX = ((mean - data[0]) / (data[data.length - 1] - data[0])) * width;
|
||||
ctx.strokeStyle = '#ff4757';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([5, 5]);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(meanX, 0);
|
||||
ctx.lineTo(meanX, height - 30);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Labels
|
||||
ctx.fillStyle = '#f0f0f5';
|
||||
ctx.font = '12px Inter';
|
||||
ctx.fillText(`Mean: ${mean.toFixed(2)} psf`, meanX + 10, 20);
|
||||
ctx.fillText(`Range: ${data[0].toFixed(1)} – ${data[data.length - 1].toFixed(1)} psf`, 10, height - 10);
|
||||
}
|
||||
|
||||
// Auto-update slope factor on input change
|
||||
document.getElementById('roof-slope').addEventListener('input', function() {
|
||||
const theta = parseFloat(this.value);
|
||||
let Cs;
|
||||
if (theta < 30) Cs = 1.0;
|
||||
else if (theta >= 30 && theta <= 50) Cs = 1.0 - (theta - 30) / 70;
|
||||
else Cs = 0.0;
|
||||
document.getElementById('slope-factor').value = Cs.toFixed(3);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user