Skip to content

Commit 7f32815

Browse files
chaitanyagiriclaude
andcommitted
seo-engine: day 12 AM, the 9 Oct brief and an Ollama title fix
New page /blog/agent-tools-today-2026-10-09/ with one scene, and a clearer title and description on is-ollama-good-for-coding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 9c6c17c commit 7f32815

41 files changed

Lines changed: 1013 additions & 178 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎blog/src/_data/media.json‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,6 +4634,18 @@
46344634
"inline": {},
46354635
"youtube": []
46364636
},
4637+
"agent-tools-today-2026-10-09": {
4638+
"title": "Agent Tools Today, 9 Oct 2026: Gemini Agent, Codex CLI 0.162.0, Step 5 Preview",
4639+
"category": "news",
4640+
"hero": {
4641+
"file": "assets/media/agent-tools-today/hero.png",
4642+
"alt": "Hand drawn sketch: a front page with five numbered lines, a clock, and a yellow character reading it out",
4643+
"prompt": "Series hero for the Agent Tools Today daily brief, drawn in code (media-src/topic-tiles.html?t=news). Reused by every brief.",
4644+
"status": "ready"
4645+
},
4646+
"inline": {},
4647+
"youtube": []
4648+
},
46374649
"cursor-alternatives": {
46384650
"title": "Cursor Alternatives: 7 AI Coding Tools to Switch To",
46394651
"category": "comparisons",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* Bright coded scene for "Agent Tools Today, 9 Oct 2026". Pairs with motion.js. */
2+
.prose figure.mg { margin: 42px 0; }
3+
.prose figure.mg img, .mg .mg-svg { display: block; width: 100%; height: auto; border: 1px solid #1A1320; border-radius: 18px; background: #fff; }
4+
.mg figcaption { font: 500 13px/1.5 "Space Grotesk", system-ui, sans-serif; color: #6B5878; padding-top: 10px; text-align: center; }
5+
.mg .mg-svg { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
6+
.mg .mg-svg text { -webkit-user-select: none; user-select: none; pointer-events: none; }
7+
.mg .mg-hit { cursor: pointer; outline: none; }
8+
.mg .mg-ring { stroke-opacity: 0; transition: stroke-opacity 0.15s; }
9+
.mg .mg-hit:focus-visible .mg-ring { stroke-opacity: 1; }
10+
@media (hover: hover) { .mg .mg-hit:hover .mg-ring { stroke-opacity: 0.5; } }
11+
@media (prefers-reduced-motion: reduce) { .mg .mg-ring { transition: none; } }
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/* Bright coded scene for "Agent Tools Today, 9 Oct 2026". Vanilla JS, no library.
2+
<figure class="mg" data-scene="NAME"> holds a still image; this script swaps in a live SVG.
3+
Plays only in view, honours reduced motion, "?mgstill" freezes each scene on its still frame. */
4+
(() => {
5+
const NS = "http://www.w3.org/2000/svg";
6+
const INK = "#1A1320", YEL = "#FFCA54", BLUE = "#6C8EF5", LIL = "#B69CFF", MINT = "#7FD8AE", SKY = "#9AD8FF", SOFT = "#F1ECF9", MUTE = "#7A6A88";
7+
const SANS = '"Space Grotesk", system-ui, sans-serif';
8+
const el = (t, a = {}, p) => { const n = document.createElementNS(NS, t); for (const k in a) n.setAttribute(k, a[k]); if (p) p.appendChild(n); return n; };
9+
const txt = (p, x, y, s, a = {}) => { const n = el("text", Object.assign({ x, y, "font-family": SANS, "font-size": 24, "font-weight": 600, fill: INK }, a), p); n.textContent = s; return n; };
10+
const cl = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v));
11+
const seg = (t, a, b) => cl((t - a) / (b - a));
12+
const oc = (x) => 1 - Math.pow(1 - x, 3);
13+
const ob = (x) => { const c = 1.70158; return 1 + (c + 1) * Math.pow(x - 1, 3) + c * Math.pow(x - 1, 2); };
14+
const io = (x) => (x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2);
15+
const bo = (x) => { const n = 7.5625, d = 2.75; if (x < 1 / d) return n * x * x; if (x < 2 / d) return n * (x -= 1.5 / d) * x + 0.75; if (x < 2.5 / d) return n * (x -= 2.25 / d) * x + 0.9375; return n * (x -= 2.625 / d) * x + 0.984375; };
16+
const tf = (n, x, y, s = 1, r = 0) => n.setAttribute("transform", `translate(${x} ${y}) rotate(${r}) scale(${s})`);
17+
const button = (g, label, fn) => {
18+
g.setAttribute("role", "button"); g.setAttribute("tabindex", "0"); g.setAttribute("aria-label", label); g.classList.add("mg-hit");
19+
g.addEventListener("click", fn);
20+
g.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fn(); } });
21+
};
22+
const strip = (svg, y, w = 680) => {
23+
el("rect", { x: (800 - w) / 2, y, width: w, height: 48, rx: 24, fill: SOFT }, svg);
24+
return txt(svg, 400, y + 31, "", { "text-anchor": "middle", "font-size": 20, "font-weight": 500 });
25+
};
26+
27+
const SC = {};
28+
29+
/* ---- the day at a glance: a blue pocket knife unfolds four tools, one per job Google gives the Gemini agent ---- */
30+
const JOBS = [
31+
["answers questions", "Job 1 of 4: it answers questions", 268, 0, -150, 130, 264],
32+
["knowledge work", "Job 2 of 4: it handles knowledge work", 268, 0, -85, 286, 168],
33+
["images and media", "Job 3 of 4: it creates images and media", 532, 180, 265, 514, 168],
34+
["writes and runs code", "Job 4 of 4: it writes and runs code", 532, 180, 330, 658, 264],
35+
];
36+
const TOOL = [
37+
(g) => { // magnifying glass
38+
el("rect", { x: 0, y: -6, width: 140, height: 12, rx: 6, fill: LIL, stroke: INK, "stroke-width": 3 }, g);
39+
el("circle", { cx: 164, cy: 0, r: 26, fill: SKY, stroke: INK, "stroke-width": 3 }, g);
40+
el("path", { d: "M150 -8 A16 16 0 0 1 164 -15", fill: "none", stroke: "#fff", "stroke-width": 3, "stroke-linecap": "round" }, g);
41+
},
42+
(g) => { // pen
43+
el("rect", { x: 0, y: -9, width: 150, height: 18, rx: 5, fill: YEL, stroke: INK, "stroke-width": 3 }, g);
44+
el("path", { d: "M150 -9 L190 0 L150 9 Z", fill: "#fff", stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g);
45+
el("path", { d: "M168 0 H190", stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, g);
46+
el("path", { d: "M128 -9 V9", stroke: INK, "stroke-width": 3 }, g);
47+
},
48+
(g) => { // paintbrush
49+
el("rect", { x: 0, y: -7, width: 122, height: 14, rx: 6, fill: MINT, stroke: INK, "stroke-width": 3 }, g);
50+
el("path", { d: "M144 -11 C160 -18 178 -10 190 0 C178 10 160 18 144 11 Z", fill: LIL, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g);
51+
el("rect", { x: 120, y: -11, width: 26, height: 22, rx: 4, fill: SOFT, stroke: INK, "stroke-width": 3 }, g);
52+
},
53+
(g) => { // screwdriver
54+
el("path", { d: "M92 -4 H164 L178 -9 H190 V9 H178 L164 4 H92 Z", fill: SOFT, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g);
55+
el("rect", { x: 0, y: -11, width: 96, height: 22, rx: 9, fill: SKY, stroke: INK, "stroke-width": 3 }, g);
56+
[28, 48, 68].forEach((x) => el("path", { d: `M${x} -5 V5`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, g));
57+
},
58+
];
59+
SC.today = {
60+
dur: 12, still: 9.5,
61+
build(svg, api) {
62+
const PY = 410, GAP = 1.6, K = 1.15;
63+
txt(svg, 400, 78, "Gemini agent", { "text-anchor": "middle", "font-size": 32, "font-weight": 700 });
64+
txt(svg, 400, 110, "four jobs, tap a tool", { "text-anchor": "middle", "font-size": 20, fill: MUTE, "font-weight": 500 });
65+
const tip = strip(svg, 522, 720);
66+
el("ellipse", { cx: 400, cy: 478, rx: 220, ry: 10, fill: SOFT }, svg);
67+
const tools = el("g", {}, svg), front = el("g", { transform: `translate(400 ${PY}) scale(${K}) translate(-400 -400)` }, svg);
68+
// the knife body, drawn over the folded tools
69+
el("circle", { cx: 572, cy: 400, r: 16, fill: "none", stroke: INK, "stroke-width": 3 }, front);
70+
el("rect", { x: 245, y: 362, width: 310, height: 76, rx: 38, fill: BLUE, stroke: INK, "stroke-width": 3 }, front);
71+
el("rect", { x: 352, y: 388, width: 96, height: 24, rx: 12, fill: "#fff", stroke: INK, "stroke-width": 3 }, front);
72+
[285, 515].forEach((x) => el("circle", { cx: x, cy: 400, r: 8, fill: YEL, stroke: INK, "stroke-width": 3 }, front));
73+
let pinned = -1;
74+
const ps = JOBS.map(([name, line, px, a0, a1, lx, ly], i) => {
75+
const g = el("g", {}, tools);
76+
const arm = el("g", {}, g); TOOL[i](arm);
77+
const lab = el("g", { opacity: 0 }, g);
78+
const w = name.length * 10.6 + 30;
79+
el("rect", { x: lx - w / 2, y: ly - 27, width: w, height: 40, rx: 12, fill: "#fff", stroke: INK, "stroke-width": 2, class: "mg-ring" }, lab);
80+
txt(lab, lx, ly, name, { "text-anchor": "middle", "font-size": 20, "font-weight": 600 });
81+
button(g, line, () => { pinned = i; api.poke(); });
82+
return { g, arm, lab, px, a0, a1, T: 1 + i * GAP };
83+
});
84+
return (t) => {
85+
let last = -1;
86+
const back = io(seg(t, 11.2, 11.9));
87+
ps.forEach((p, i) => {
88+
const s = t - p.T, open = s < 0 ? 0 : ob(seg(s, 0, 0.9)) * (1 - back);
89+
const nudge = pinned === i && s >= 0.9 && back === 0 ? (i < 2 ? -6 : 6) : 0;
90+
p.arm.setAttribute("transform", `translate(${p.px} ${PY}) rotate(${p.a0 + (p.a1 - p.a0) * open + nudge}) scale(${K})`);
91+
p.arm.setAttribute("opacity", s < 0 || back >= 1 ? 0 : 1);
92+
p.lab.setAttribute("opacity", seg(s, 0.7, 1.2) * (1 - seg(t, 11.0, 11.3)));
93+
p.g.style.pointerEvents = s >= 0.9 && back === 0 ? "auto" : "none";
94+
if (s >= 0.9) last = i;
95+
});
96+
const show = pinned >= 0 ? pinned : last;
97+
tip.textContent = show < 0 || (pinned < 0 && back > 0) ? "Google Cloud calls it a “single, universal agent for work”" : JOBS[show][1];
98+
};
99+
},
100+
};
101+
102+
/* ---- player ---- */
103+
const q = new URLSearchParams(location.search), frozen = q.has("mgstill"), fixed = parseFloat(q.get("mgstill"));
104+
const calm = matchMedia("(prefers-reduced-motion: reduce)").matches;
105+
const mount = (fig) => {
106+
const sc = SC[fig.dataset.scene], img = fig.querySelector("img"); if (!sc || !img) return;
107+
const W = sc.w || 800, H = sc.h || 600;
108+
const svg = el("svg", { viewBox: `0 0 ${W} ${H}`, class: "mg-svg", role: "group", "aria-label": img.alt || "" });
109+
svg.style.aspectRatio = `${W} / ${H}`;
110+
el("rect", { width: W, height: H, fill: "#fff" }, svg);
111+
img.replaceWith(svg);
112+
let off = 0, raf = 0, seen = false, held = calm;
113+
const base = performance.now(), clock = () => (performance.now() - base) / 1000;
114+
let draw = () => {};
115+
const frame = () => { const now = clock(); draw(held ? sc.still : (((now + off) % sc.dur) + sc.dur) % sc.dur, now); };
116+
const tick = () => { cancelAnimationFrame(raf); frame(); if (seen && !held) raf = requestAnimationFrame(tick); };
117+
const api = { now: clock, seek: (s) => { off = s - clock(); held = false; tick(); }, poke: () => { held = false; tick(); } };
118+
draw = sc.build(svg, api);
119+
if (frozen) { draw(isNaN(fixed) ? sc.still : fixed, 0); return; }
120+
new IntersectionObserver(([e]) => {
121+
seen = e.isIntersecting;
122+
if (seen) { tick(); if (!fig.dataset.sent && window.posthog) { fig.dataset.sent = 1; window.posthog.capture("blog_scene_view", { slug: location.pathname.split("/").filter(Boolean).pop(), scene: fig.dataset.scene }); } }
123+
else cancelAnimationFrame(raf);
124+
}, { threshold: 0.25 }).observe(fig);
125+
svg.addEventListener("click", () => { if (!fig.dataset.hit && window.posthog) { fig.dataset.hit = 1; window.posthog.capture("blog_scene_interact", { slug: location.pathname.split("/").filter(Boolean).pop(), scene: fig.dataset.scene }); } });
126+
frame();
127+
};
128+
const go = () => document.querySelectorAll("figure.mg[data-scene]").forEach(mount);
129+
const fonts = document.fonts && document.fonts.load ? Promise.all([document.fonts.load('700 32px "Space Grotesk"'), document.fonts.load('500 20px "Space Grotesk"'), document.fonts.load('600 18px "Space Grotesk"')]).catch(() => {}) : Promise.resolve();
130+
const start = () => fonts.then(go, go);
131+
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start); else start();
132+
})();
109 KB
Loading

0 commit comments

Comments
 (0)