Skip to content

Commit 2468e4f

Browse files
authored
Merge pull request #22 from 42devops/feat/pretext-dom-obstacles
feat: upgrade Pretext engine with DOM obstacle wrapping and CJK sub-chunk fitting
2 parents 9765e4d + 1c7a716 commit 2468e4f

3 files changed

Lines changed: 79 additions & 8 deletions

File tree

css/screen.css

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
/* Light Theme - Kami Warm Parchment Canvas & Ink Blue Accent */
1313
--bg-page: #f5f4ed; /* Warm parchment canvas */
1414
--bg-card: #faf9f5; /* Warm ivory container */
15+
--bg-card-rgb: 250, 249, 245;
1516
--bg-subtle: #e8e6dc; /* Warm sand interactive surface */
1617
--bg-code: #1c1c1a; /* Deep warm charcoal for code */
1718
--border-color: #e8e6dc; /* Primary warm border */
@@ -43,6 +44,7 @@
4344
/* Dark Theme - Kami Dark Surface & Warm Charcoal */
4445
--bg-page: #141413; /* Deep dark warm background */
4546
--bg-card: #242422; /* Dark warm surface */
47+
--bg-card-rgb: 36, 36, 34;
4648
--bg-subtle: #2e2e2a; /* Dark warm sand */
4749
--bg-code: #0f0f0e; /* Dark code background */
4850
--border-color: rgba(232, 230, 220, 0.12);
@@ -191,10 +193,26 @@ body {
191193
.hero-banner {
192194
position: relative;
193195
text-align: center;
194-
padding: 5.5rem 0 5rem 0;
196+
padding: 4rem 1rem;
195197
margin-bottom: 2.5rem;
196198
overflow: hidden;
197199
border-radius: var(--radius-lg);
200+
background: var(--bg-card);
201+
border: 1px solid var(--border-color);
202+
}
203+
204+
.hero-content {
205+
position: relative;
206+
z-index: 2;
207+
max-width: 680px;
208+
margin: 0 auto;
209+
padding: 1.25rem 1.75rem;
210+
background: rgba(var(--bg-card-rgb, 250, 249, 245), 0.85);
211+
backdrop-filter: blur(8px);
212+
-webkit-backdrop-filter: blur(8px);
213+
border: 1px solid var(--border-subtle);
214+
border-radius: var(--radius-md);
215+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.03);
198216
}
199217

200218
.hero-pretext-canvas {

index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
<section class="hero-banner">
77
<canvas id="hero-pretext-canvas" class="hero-pretext-canvas"></canvas>
8+
<div class="hero-content pretext-obstacle">
9+
<h1 class="hero-title" style="margin-bottom: 0.75rem;">Infrastructure, Systems & Engineering</h1>
10+
<p class="hero-subtitle" style="margin: 0 auto;">Notes on Kubernetes, DevOps, Cloud Infrastructure, and Software Architecture.</p>
11+
</div>
812
</section>
913
<script src="/js/dragon.js?v={{ site.time | date: '%s' }}" defer></script>
1014
<script src="/js/hero-pretext.js?v={{ site.time | date: '%s' }}" defer></script>

js/hero-pretext.js

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,28 +122,44 @@
122122
const lineHeight = 22;
123123
let wordIdx = 0;
124124

125-
// Build list of obstacle circles from dragon segments
126-
const obstacles = [];
125+
// Build list of obstacles (dragon circles + DOM element rectangles)
126+
const circularObstacles = [];
127127
if (dragon && dragon.segments) {
128128
// Head obstacle
129129
const head = dragon.segments[0];
130-
obstacles.push({ x: head.x, y: head.y, r: 48 });
130+
circularObstacles.push({ x: head.x, y: head.y, r: 48 });
131131

132132
// Body segment obstacles (every 3rd segment)
133133
for (let i = 2; i < dragon.segments.length; i += 3) {
134134
const seg = dragon.segments[i];
135-
obstacles.push({ x: seg.x, y: seg.y, r: Math.max(16, seg.width * 0.6) });
135+
circularObstacles.push({ x: seg.x, y: seg.y, r: Math.max(16, seg.width * 0.6) });
136136
}
137137
}
138138

139+
// Query DOM obstacles inside container
140+
const domObstacles = [];
141+
const containerRect = container.getBoundingClientRect();
142+
const obstacleElements = container.querySelectorAll('.pretext-obstacle, .hero-title, .hero-subtitle');
143+
obstacleElements.forEach(el => {
144+
const rect = el.getBoundingClientRect();
145+
const pad = 12; // padding around UI elements
146+
const top = rect.top - containerRect.top - pad;
147+
const bottom = rect.bottom - containerRect.top + pad;
148+
const left = rect.left - containerRect.left - pad;
149+
const right = rect.right - containerRect.left + pad;
150+
if (right > 0 && left < width && bottom > 0 && top < height) {
151+
domObstacles.push({ left, right, top, bottom });
152+
}
153+
});
154+
139155
for (let y = 18; y < height; y += lineHeight) {
140156
let x = 12;
141157

142158
while (x < width - 12) {
143159
let availableSpan = width - 12 - x;
144160

145-
// Subtract dragon segment obstacles intersecting line at y
146-
for (let obs of obstacles) {
161+
// 1. Subtract dragon circular segment obstacles intersecting line at y
162+
for (let obs of circularObstacles) {
147163
const dy = Math.abs(y - obs.y);
148164
if (dy < obs.r) {
149165
const dx = Math.sqrt(obs.r * obs.r - dy * dy);
@@ -161,6 +177,20 @@
161177
}
162178
}
163179

180+
// 2. Subtract DOM rectangular obstacles intersecting line at y
181+
for (let obs of domObstacles) {
182+
if (y >= obs.top && y <= obs.bottom) {
183+
if (x < obs.right && x + availableSpan > obs.left) {
184+
if (x < obs.left) {
185+
availableSpan = obs.left - x;
186+
} else {
187+
x = obs.right;
188+
availableSpan = width - 12 - x;
189+
}
190+
}
191+
}
192+
}
193+
164194
let count = 0;
165195
let currentSpan = 0;
166196
let checkIdx = wordIdx;
@@ -173,7 +203,26 @@
173203
}
174204

175205
if (count === 0) {
176-
x += 16;
206+
// If phrase doesn't fit in gap, try CJK/character sub-chunk fitting
207+
const phrase = phraseStream[wordIdx];
208+
let subFit = "";
209+
let subWidth = 0;
210+
for (let char of phrase) {
211+
const charWidth = ctx.measureText(char).width;
212+
if (subWidth + charWidth <= availableSpan) {
213+
subFit += char;
214+
subWidth += charWidth;
215+
} else {
216+
break;
217+
}
218+
}
219+
220+
if (subFit.length > 0 && availableSpan > 20) {
221+
ctx.fillText(subFit, x, y);
222+
x += subWidth + 8;
223+
} else {
224+
x += 16;
225+
}
177226
continue;
178227
}
179228

0 commit comments

Comments
 (0)