diff --git a/blog/src/_data/media.json b/blog/src/_data/media.json index f74aaf01c5..1f77259780 100644 --- a/blog/src/_data/media.json +++ b/blog/src/_data/media.json @@ -5336,5 +5336,16 @@ "status": "ready" }, "inline": {} + }, + "gpt-6-1-terra": { + "title": "GPT-6.1 Terra: Price, Specs and How to Use It in Codex (Oct 2026)", + "category": "concepts", + "hero": { + "file": "assets/media/gpt-6-1-terra/hero.png", + "alt": "Title card on white. GPT-6.1 Terra in large ink type, a Concepts pill, the line Price, specs and Codex setup, Checked 27 Oct 2026, and a white card with a picture, a pointer arrow and a pencil beside a yellow tag reading $1 in, $5 out", + "prompt": "Still of the hero scene in assets/media/gpt-6-1-terra/motion.js.", + "status": "ready" + }, + "inline": {} } } diff --git a/blog/src/assets/media/gpt-6-1-terra/dial.png b/blog/src/assets/media/gpt-6-1-terra/dial.png new file mode 100644 index 0000000000..1dc3367cfa Binary files /dev/null and b/blog/src/assets/media/gpt-6-1-terra/dial.png differ diff --git a/blog/src/assets/media/gpt-6-1-terra/hero.png b/blog/src/assets/media/gpt-6-1-terra/hero.png new file mode 100644 index 0000000000..180bcb4450 Binary files /dev/null and b/blog/src/assets/media/gpt-6-1-terra/hero.png differ diff --git a/blog/src/assets/media/gpt-6-1-terra/lineup.png b/blog/src/assets/media/gpt-6-1-terra/lineup.png new file mode 100644 index 0000000000..a44ab86bc2 Binary files /dev/null and b/blog/src/assets/media/gpt-6-1-terra/lineup.png differ diff --git a/blog/src/assets/media/gpt-6-1-terra/motion.css b/blog/src/assets/media/gpt-6-1-terra/motion.css new file mode 100644 index 0000000000..ecaaf508aa --- /dev/null +++ b/blog/src/assets/media/gpt-6-1-terra/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scenes for "GPT-6.1 Terra". Pairs with motion.js. */ +.prose figure.mg { margin: 42px 0; } +.prose figure.mg img, .mg .mg-svg { display: block; width: 100%; height: auto; border: 1px solid #1A1320; border-radius: 18px; background: #fff; } +.mg figcaption { font: 500 13px/1.5 "Space Grotesk", system-ui, sans-serif; color: #6B5878; padding-top: 10px; text-align: center; } +.mg .mg-svg { touch-action: manipulation; -webkit-tap-highlight-color: transparent; } +.mg .mg-svg text { -webkit-user-select: none; user-select: none; pointer-events: none; } +.mg .mg-hit { cursor: pointer; outline: none; } +.mg [role="slider"] { cursor: grab; touch-action: none; } +.mg .mg-ring { stroke-opacity: 0; transition: stroke-opacity 0.15s; } +.mg .mg-hit:focus-visible .mg-ring { stroke-opacity: 1; } +.mg [role="slider"]:focus-visible circle:nth-child(2) { stroke-width: 5; } +@media (hover: hover) { .mg .mg-hit:hover .mg-ring { stroke-opacity: 0.5; } } +@media (prefers-reduced-motion: reduce) { .mg .mg-ring { transition: none; } } diff --git a/blog/src/assets/media/gpt-6-1-terra/motion.js b/blog/src/assets/media/gpt-6-1-terra/motion.js new file mode 100644 index 0000000000..b8aa4bb4a7 --- /dev/null +++ b/blog/src/assets/media/gpt-6-1-terra/motion.js @@ -0,0 +1,279 @@ +/* Bright coded scenes for "GPT-6.1 Terra". Vanilla JS, no library. +
holds a still image; this script swaps in a live SVG. + Plays only in view, honours reduced motion, "?mgstill" freezes each scene on its still frame. */ +(() => { + const NS = "http://www.w3.org/2000/svg"; + const INK = "#1A1320", YEL = "#FFCA54", BLUE = "#6C8EF5", LIL = "#B69CFF", MINT = "#7FD8AE", SKY = "#9AD8FF", SOFT = "#F1ECF9", MUTE = "#7A6A88", CAP = "#6B5878"; + const SANS = '"Space Grotesk", system-ui, sans-serif', MONO = '"JetBrains Mono", ui-monospace, monospace'; + 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; }; + 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; }; + const cl = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v)); + const seg = (t, a, b) => cl((t - a) / (b - a)); + const oc = (x) => 1 - Math.pow(1 - x, 3); + const ob = (x) => { const c = 1.70158; return 1 + (c + 1) * Math.pow(x - 1, 3) + c * Math.pow(x - 1, 2); }; + const io = (x) => (x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2); + const tf = (n, x, y, s = 1, r = 0) => n.setAttribute("transform", `translate(${x} ${y}) rotate(${r}) scale(${s})`); + const button = (g, label, fn) => { + g.setAttribute("role", "button"); g.setAttribute("tabindex", "0"); g.setAttribute("aria-label", label); g.classList.add("mg-hit"); + g.addEventListener("click", fn); + g.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fn(); } }); + }; + + /* ---- the three Terra icons (a picture, a plain arrow pointer, a pencil), each drawn around 0,0 ---- */ + const ICONS = [ + (g) => { + el("rect", { x: -26, y: -20, width: 52, height: 40, rx: 6, fill: SKY, stroke: INK, "stroke-width": 3 }, g); + el("circle", { cx: 11, cy: -7, r: 6, fill: YEL, stroke: INK, "stroke-width": 2.5 }, g); + el("path", { d: "M-24 18 L-8 1 L3 12 L11 5 L24 18 Z", fill: MINT, stroke: INK, "stroke-width": 2.5, "stroke-linejoin": "round" }, g); + }, + (g) => { + el("path", { d: "M-11 -23 L-11 15 L-1 6 L6 21 L13 18 L6 3 L19 3 Z", fill: LIL, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g); + }, + (g) => { + const p = el("g", { transform: "rotate(-45)" }, g); + el("rect", { x: -32, y: -8, width: 10, height: 16, rx: 3, fill: LIL, stroke: INK, "stroke-width": 3 }, p); + el("rect", { x: -22, y: -8, width: 36, height: 16, fill: YEL, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, p); + el("path", { d: "M14 -8 L30 0 L14 8 Z", fill: "#fff", stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, p); + el("path", { d: "M25 -2.5 L30 0 L25 2.5 Z", fill: INK, stroke: INK, "stroke-width": 2, "stroke-linejoin": "round" }, p); + }, + ]; + + /* ---- a price tag, centred on 0,0, with a punched hole on the left ---- */ + const tagShape = (g, w, h, fill) => { + const L = -w / 2, R = w / 2, T = -h / 2, B = h / 2, n = Math.min(h / 2, 34); + el("path", { d: `M${L} 0 L${L + n} ${T} H${R - 14} Q${R} ${T} ${R} ${T + 14} V${B - 14} Q${R} ${B} ${R - 14} ${B} H${L + n} Z`, fill, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g); + el("circle", { cx: L + n * 0.85, cy: 0, r: 7, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, g); + return L + n * 0.85 + 18; + }; + + const SC = {}; + + /* ---- 1. the GPT-6 lineup, tall to short; Terra lifts and gets its tag ---- */ + SC.lineup = { + dur: 9, still: 8.9, + build(svg, api) { + const BOX = [["Astra", 340, LIL], ["Sol", 280, BLUE], ["Terra", 210, SKY], ["Luna", 140, SOFT]]; + const base = 470, w = 120, gap = 50, x0 = 85, LIFT = 28; + el("path", { d: "M60 470 H740", stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, svg); + const boxes = BOX.map(([name, h, col], i) => { + const x = x0 + i * (w + gap), g = el("g", {}, svg); + if (i === 2) el("rect", { x: x - 9, y: base - h - 9, width: w + 18, height: h + 18, rx: 22, fill: "none", stroke: INK, "stroke-width": 2.5, "stroke-dasharray": "4 6", class: "mg-ring" }, g); + const r = el("rect", { x, y: base - h, width: w, height: h, rx: 16, fill: col, stroke: INK, "stroke-width": 3 }, g); + txt(svg, x + w / 2, 512, name, { "text-anchor": "middle", "font-size": 26, "font-weight": 700 }); + return { g, r, h, d: 0.1 + i * 0.15 }; + }); + button(boxes[2].g, "Terra: replay the lift", () => api.seek(1.2)); + const cx = x0 + 2 * (w + gap) + w / 2; + const tag = el("g", {}, svg); + const tx = tagShape(tag, 160, 80, YEL); + txt(tag, tx + 2, -6, "Fast and", { "font-size": 21, "font-weight": 700 }); + txt(tag, tx + 2, 21, "efficient", { "font-size": 21, "font-weight": 700 }); + const icons = ICONS.map((f, i) => { + const g = el("g", {}, svg); + el("rect", { x: -32, y: -32, width: 64, height: 64, rx: 14, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, g); + const ic = el("g", { transform: "scale(0.8)" }, g); f(ic); + return { g, y: 130 + i * 76 }; + }); + return (t) => { + boxes.forEach((b, i) => { + const k = Math.max(0, ob(seg(t, b.d, b.d + 0.6))), hh = b.h * k; + b.r.setAttribute("height", hh); b.r.setAttribute("y", base - hh); b.r.setAttribute("rx", Math.min(16, hh / 2)); + b.r.setAttribute("opacity", k > 0 ? 1 : 0); + }); + const lift = ob(seg(t, 1.4, 2.1)); + boxes[2].g.setAttribute("transform", `translate(0 ${-LIFT * lift})`); + const top = base - 210 - LIFT * lift - 44, d = ob(seg(t, 2.2, 2.9)); + tf(tag, cx, -60 + (top + 60) * d, 1, -3 * d); + tag.setAttribute("opacity", t >= 2.2 ? 1 : 0); + icons.forEach((n, i) => { const k = ob(seg(t, 3.0 + i * 0.25, 3.45 + i * 0.25)); tf(n.g, 655, n.y, Math.max(0, k)); n.g.setAttribute("opacity", k > 0 ? 1 : 0); }); + }; + }, + }; + + /* ---- 2. old price tag, new price tag in front ---- */ + SC.tags = { + dur: 9, still: 8.9, + build(svg, api) { + const mk = (name, a, b, fill) => { + const g = el("g", {}, svg), x = tagShape(g, 400, 230, fill); + txt(g, x, -50, name, { "font-family": MONO, "font-size": 30, "font-weight": 700 }); + txt(g, x, 18, a, { "font-family": MONO, "font-size": 42, "font-weight": 700 }); + txt(g, x, 76, b, { "font-family": MONO, "font-size": 42, "font-weight": 700 }); + return g; + }; + const old = mk("GPT-5.6 Terra", "$2 in", "$12 out", "#fff"); + const neu = mk("GPT-6.1 Terra", "$1 in", "$5 out", YEL); + const P0 = [300, 232, 1, -5], P1 = [512, 392, 0.8, 4]; + const lab = el("g", {}, svg); + el("rect", { x: -98, y: -24, width: 196, height: 48, rx: 24, fill: MINT, stroke: INK, "stroke-width": 2.5 }, lab); + txt(lab, 0, 8, "per 1M tokens", { "text-anchor": "middle", "font-size": 21, "font-weight": 700 }); + const hit = el("g", {}, svg); + el("rect", { x: -172, y: -104, width: 344, height: 208, rx: 20, fill: "#fff", "fill-opacity": 0 }, hit); + el("rect", { x: -182, y: -114, width: 364, height: 228, rx: 26, fill: "none", stroke: INK, "stroke-width": 2.5, "stroke-dasharray": "4 6", class: "mg-ring" }, hit); + tf(hit, P1[0], P1[1], 1, P1[3]); + let flip = 0, flipAt = -99, user = false; + button(hit, "Flip between the two price tags", () => { user = true; flip = 1 - flip; flipAt = api.now(); api.poke(); }); + const lerp = (A, B, s) => A.map((v, i) => v + (B[i] - v) * s); + return (t, now) => { + const tt = user ? 9 : t; + const k = io(seg(now - flipAt, 0, 0.7)), s = flip ? k : 1 - k; + const a = lerp(P0, P1, s), b = lerp(P1, P0, s), arc = Math.sin(Math.PI * s) * 40; + const pop = Math.max(0, ob(seg(tt, 0.2, 0.8))); + tf(old, a[0], a[1] + (s > 0.5 ? -arc : arc * 0.3), a[2] * pop, a[3]); old.setAttribute("opacity", pop > 0 ? 1 : 0); + const slide = oc(seg(tt, 1.4, 2.4)); + tf(neu, b[0] + 460 * (1 - slide), b[1] + (s > 0.5 ? arc * 0.3 : -arc), b[2], b[3] + 10 * (1 - slide)); + neu.setAttribute("opacity", tt >= 1.4 ? 1 : 0); + if (s > 0.5) svg.insertBefore(old, lab); else svg.insertBefore(neu, lab); + const l = Math.max(0, ob(seg(tt, 3.0, 3.5))); + tf(lab, 236, 524, l); lab.setAttribute("opacity", l > 0 ? 1 : 0); + }; + }, + }; + + /* ---- 3. the reasoning effort dial ---- */ + SC.dial = { + dur: 10, still: 9.9, + build(svg, api) { + const C = [400, 360], R = 150, A = [150, 198, 246, 294, 342, 390], N = ["none", "low", "medium", "high", "xhigh", "max"]; + const rad = (d) => (d * Math.PI) / 180, P = (d, r) => [C[0] + Math.cos(rad(d)) * r, C[1] + Math.sin(rad(d)) * r]; + el("rect", { x: 90, y: 60, width: 620, height: 480, rx: 28, fill: "#fff", stroke: INK, "stroke-width": 3 }, svg); + const dial = el("g", { role: "slider", tabindex: "0", "aria-label": "Reasoning effort dial", "aria-valuemin": 0, "aria-valuemax": 5, class: "mg-hit" }, svg); + el("circle", { cx: C[0], cy: C[1], r: 205, fill: "#fff", "fill-opacity": 0 }, dial); + el("circle", { cx: C[0], cy: C[1], r: 176, fill: "none", stroke: INK, "stroke-width": 2.5, "stroke-dasharray": "4 6", class: "mg-ring" }, dial); + el("circle", { cx: C[0], cy: C[1], r: R, fill: SOFT, stroke: INK, "stroke-width": 3 }, dial); + const [ax, ay] = P(A[0], 112), [bx, by] = P(A[5], 112); + el("path", { d: `M${ax} ${ay} A112 112 0 1 1 ${bx} ${by}`, fill: "none", stroke: "#fff", "stroke-width": 14, "stroke-linecap": "round" }, dial); + const anchor = ["end", "end", "middle", "middle", "start", "start"]; + const glow = el("rect", { rx: 18, fill: YEL, stroke: INK, "stroke-width": 2.5 }, dial); + const halo = el("circle", { r: 18, fill: "none", stroke: YEL, "stroke-width": 5 }, dial); + const dots = A.map((d, i) => { + const [x, y] = P(d, R), [lx, ly] = P(d, i === 2 || i === 3 ? 206 : 192); + txt(dial, lx, ly + 8, N[i], { "text-anchor": anchor[i], "font-family": MONO, "font-size": 24, "font-weight": 700 }); + return el("circle", { cx: x, cy: y, r: 9, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, dial); + }); + const ml = dial.querySelectorAll("text")[2], mb = ml.getBBox(); + glow.setAttribute("x", mb.x - 12); glow.setAttribute("y", mb.y - 5); glow.setAttribute("width", mb.width + 24); glow.setAttribute("height", mb.height + 10); + dial.insertBefore(glow, ml); + const [hx, hy] = P(A[2], R); halo.setAttribute("cx", hx); halo.setAttribute("cy", hy); + const def = txt(dial, mb.x + mb.width / 2, mb.y - 18, "default", { "text-anchor": "middle", "font-size": 18, "font-weight": 500, fill: MUTE }); + const needle = el("g", {}, dial); + el("path", { d: "M0 -10 L116 0 L0 10 Z", fill: INK, stroke: INK, "stroke-width": 2, "stroke-linejoin": "round" }, needle); + el("circle", { r: 20, fill: YEL, stroke: INK, "stroke-width": 3 }, needle); + let ui = null, from = A[2], at = -99, cur = A[2]; + const move = (i) => { from = cur; ui = (i + 6) % 6; at = api.now(); api.poke(); }; + dial.addEventListener("click", () => move((ui == null ? 2 : ui) + 1)); + dial.addEventListener("keydown", (e) => { + const i = ui == null ? 2 : ui; + if (e.key === "ArrowRight" || e.key === "ArrowUp") { e.preventDefault(); move(Math.min(5, i + 1)); } + else if (e.key === "ArrowLeft" || e.key === "ArrowDown") { e.preventDefault(); move(Math.max(0, i - 1)); } + else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); move(i + 1); } + }); + return (t, now) => { + cur = ui != null ? from + (A[ui] - from) * io(seg(now - at, 0, 0.5)) : A[2] + (A[5] - A[2]) * (io(seg(t, 2.5, 4.5)) - io(seg(t, 5.5, 7.5))); + tf(needle, C[0], C[1], 1, cur); + const g = ui != null ? 1 : oc(seg(t, 0.6, 1.3)); + glow.setAttribute("opacity", g); def.setAttribute("opacity", g); + halo.setAttribute("opacity", g); halo.setAttribute("r", 17 + 3 * Math.sin(now * 3) * g); + let near = 0; A.forEach((d, i) => { if (Math.abs(d - cur) < Math.abs(A[near] - cur)) near = i; }); + dots.forEach((n, i) => n.setAttribute("fill", i === 2 && g > 0.5 ? YEL : i === near && Math.abs(A[i] - cur) < 6 ? BLUE : "#fff")); + dial.setAttribute("aria-valuenow", near); dial.setAttribute("aria-valuetext", N[near]); + }; + }, + }; + + /* ---- 4. switch the Codex CLI to Terra ---- */ + SC.switch = { + dur: 10, still: 9.9, + build(svg, api) { + const X = 70, Y = 60, W = 660, H = 260; + el("rect", { x: X, y: Y, width: W, height: H, rx: 20, fill: "#fff" }, svg); + el("path", { d: `M${X} ${Y + 50} V${Y + 20} Q${X} ${Y} ${X + 20} ${Y} H${X + W - 20} Q${X + W} ${Y} ${X + W} ${Y + 20} V${Y + 50} Z`, fill: SOFT }, svg); + el("path", { d: `M${X} ${Y + 50} H${X + W}`, stroke: INK, "stroke-width": 2.5 }, svg); + el("rect", { x: X, y: Y, width: W, height: H, rx: 20, fill: "none", stroke: INK, "stroke-width": 3 }, svg); + [102, 126, 150].forEach((x) => el("circle", { cx: x, cy: Y + 25, r: 7, fill: "#fff", stroke: INK, "stroke-width": 2 }, svg)); + const chip = el("rect", { x: 560, y: 70, width: 150, height: 30, rx: 15, fill: "#fff", stroke: INK, "stroke-width": 2 }, svg); + const ph = el("rect", { x: 595, y: 81, width: 80, height: 8, rx: 4, fill: LIL }, svg); + const cn = txt(svg, 635, 92, "6.1 Terra", { "text-anchor": "middle", "font-family": MONO, "font-size": 18, "font-weight": 700 }); + txt(svg, 108, 200, "$", { "font-family": MONO, "font-size": 30, "font-weight": 700, fill: MUTE }); + const CMD = "codex -m gpt-6.1-terra"; + const line = txt(svg, 145, 200, CMD, { "font-family": MONO, "font-size": 30, "font-weight": 700 }); + const cw = line.getComputedTextLength() / CMD.length || 18; + const caret = el("rect", { y: 174, width: 15, height: 34, rx: 2, fill: BLUE }, svg); + const card = el("g", {}, svg); + el("rect", { x: 150, y: 370, width: 500, height: 80, rx: 18, fill: "#fff", stroke: INK, "stroke-width": 3 }, card); + const tick = el("circle", { cx: 200, cy: 410, r: 22, fill: "#fff", stroke: INK, "stroke-width": 3 }, card); + const mark = el("path", { d: "M189 411 L197 419 L212 402", fill: "none", stroke: INK, "stroke-width": 4, "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-dasharray": 32 }, card); + txt(card, 240, 418, "Codex CLI 0.159.0 or later", { "font-family": MONO, "font-size": 22, "font-weight": 700 }); + const rb = el("g", {}, svg); + el("rect", { x: 595, y: 485, width: 140, height: 54, rx: 27, fill: SKY, stroke: INK, "stroke-width": 3 }, rb); + el("rect", { x: 589, y: 479, width: 152, height: 66, rx: 33, fill: "none", stroke: INK, "stroke-width": 2.5, "stroke-dasharray": "4 6", class: "mg-ring" }, rb); + txt(rb, 665, 519, "Replay", { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + button(rb, "Replay", () => api.seek(0.01)); + return (t, now) => { + const n = Math.round(CMD.length * seg(t, 0.6, 3.4)); + line.textContent = CMD.slice(0, n); + caret.setAttribute("x", 145 + cw * n + 2); + caret.setAttribute("opacity", t < 3.4 || Math.floor(now * 2) % 2 === 0 ? 1 : 0); + const c = oc(seg(t, 4.0, 4.6)); + card.setAttribute("opacity", c); card.setAttribute("transform", `translate(0 ${30 * (1 - c)})`); + const k = seg(t, 4.8, 5.3); + tick.setAttribute("fill", k > 0.2 ? MINT : "#fff"); tick.setAttribute("transform", `rotate(0) translate(200 410) scale(${1 + 0.18 * Math.sin(Math.PI * k)}) translate(-200 -410)`); + mark.setAttribute("stroke-dashoffset", 32 * (1 - k)); + const m = io(seg(t, 5.6, 6.2)); + ph.setAttribute("opacity", 1 - m); ph.setAttribute("transform", `translate(0 ${-8 * m})`); + cn.setAttribute("opacity", m); cn.setAttribute("transform", `translate(0 ${10 * (1 - m)})`); + chip.setAttribute("fill", m > 0.5 ? YEL : "#fff"); + }; + }, + }; + + /* ---- title card, 16 by 9 ---- */ + SC.hero = { + w: 960, h: 540, dur: 1, still: 0, + build(svg) { + el("rect", { x: 64, y: 70, width: 132, height: 40, rx: 20, fill: SOFT, stroke: INK, "stroke-width": 2 }, svg); + txt(svg, 130, 97, "Concepts", { "text-anchor": "middle", "font-size": 19, "font-weight": 700 }); + txt(svg, 62, 210, "GPT-6.1 Terra", { "font-family": MONO, "font-size": 64, "font-weight": 700 }); + el("path", { d: "M66 238 H520", stroke: YEL, "stroke-width": 14, "stroke-linecap": "round" }, svg); + txt(svg, 64, 300, "Price, specs and Codex setup", { "font-size": 30, "font-weight": 500, fill: MUTE }); + txt(svg, 64, 470, "Checked 27 Oct 2026", { "font-size": 20, "font-weight": 500, fill: CAP }); + el("rect", { x: 620, y: 60, width: 140, height: 320, rx: 22, fill: "#fff", stroke: INK, "stroke-width": 3 }, svg); + ICONS.forEach((f, i) => { const g = el("g", {}, svg); f(g); tf(g, 690, 125 + i * 95, 1.25); }); + const tag = el("g", {}, svg), x = tagShape(tag, 260, 64, YEL); + txt(tag, x - 2, 9, "$1 in, $5 out", { "font-family": MONO, "font-size": 25, "font-weight": 700 }); + tf(tag, 790, 445, 1, -5); + return () => {}; + }, + }; + + /* ---- player ---- */ + const q = new URLSearchParams(location.search), frozen = q.has("mgstill"), fixed = parseFloat(q.get("mgstill")); + const calm = matchMedia("(prefers-reduced-motion: reduce)").matches; + const mount = (fig) => { + const sc = SC[fig.dataset.scene], img = fig.querySelector("img"); if (!sc || !img) return; + const W = sc.w || 800, H = sc.h || 600; + const svg = el("svg", { viewBox: `0 0 ${W} ${H}`, class: "mg-svg", role: "group", "aria-label": img.alt || "" }); + svg.style.aspectRatio = `${W} / ${H}`; + el("rect", { width: W, height: H, fill: "#fff" }, svg); + img.replaceWith(svg); + let off = 0, raf = 0, seen = false, held = calm; + const base = performance.now(), clock = () => (performance.now() - base) / 1000; + let draw = () => {}; + const frame = () => { const now = clock(); draw(held ? sc.still : (((now + off) % sc.dur) + sc.dur) % sc.dur, now); }; + const tick = () => { cancelAnimationFrame(raf); frame(); if (seen && !held) raf = requestAnimationFrame(tick); }; + const api = { now: clock, seek: (s) => { off = s - clock(); held = false; tick(); }, poke: () => { held = false; tick(); } }; + draw = sc.build(svg, api); + if (frozen) { draw(isNaN(fixed) ? sc.still : fixed, 0); return; } + new IntersectionObserver(([e]) => { + seen = e.isIntersecting; + 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 }); } } + else cancelAnimationFrame(raf); + }, { threshold: 0.25 }).observe(fig); + 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 }); } }); + frame(); + }; + const go = () => document.querySelectorAll("figure.mg[data-scene]").forEach(mount); + 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('700 20px "JetBrains Mono"')]).catch(() => {}) : Promise.resolve(); + const start = () => fonts.then(go, go); + if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start); else start(); +})(); diff --git a/blog/src/assets/media/gpt-6-1-terra/switch.png b/blog/src/assets/media/gpt-6-1-terra/switch.png new file mode 100644 index 0000000000..fa5deedbca Binary files /dev/null and b/blog/src/assets/media/gpt-6-1-terra/switch.png differ diff --git a/blog/src/assets/media/gpt-6-1-terra/tags.png b/blog/src/assets/media/gpt-6-1-terra/tags.png new file mode 100644 index 0000000000..5b9ae7a458 Binary files /dev/null and b/blog/src/assets/media/gpt-6-1-terra/tags.png differ diff --git a/blog/src/posts/codex-computer-use.md b/blog/src/posts/codex-computer-use.md index ff92a9b6e1..f0528d66df 100644 --- a/blog/src/posts/codex-computer-use.md +++ b/blog/src/posts/codex-computer-use.md @@ -47,7 +47,7 @@ Four steps in the ChatGPT desktop app, from the docs: 3. Turn on the Computer Use server and skill toggles, then select **Try now**. 4. On macOS, grant **Screen Recording** so it can see apps and **Accessibility** so it can click, type and navigate. -Then mention `@Computer` or an app, as in `@Chrome`, in your prompt and name the exact window or flow. The docs suggest GPT-6 Astra, where your model picker has it, for hard tasks that depend on screenshots. +Then mention `@Computer` or an app, as in `@Chrome`, in your prompt and name the exact window or flow. The docs suggest GPT-6 Astra, where your model picker has it, for hard tasks that depend on screenshots. OpenAI's cheaper [GPT-6.1 Terra](/blog/gpt-6-1-terra/), released on 26 Oct 2026, is also aimed at computer use. ## Which plans include Codex computer use? diff --git a/blog/src/posts/gpt-6-1-terra.md b/blog/src/posts/gpt-6-1-terra.md new file mode 100644 index 0000000000..2abd1f6e4d --- /dev/null +++ b/blog/src/posts/gpt-6-1-terra.md @@ -0,0 +1,112 @@ +--- +title: "GPT-6.1 Terra: Price, Specs and How to Use It in Codex (Oct 2026)" +seoTitle: "GPT-6.1 Terra (Oct 2026): Price, Context Window, Codex Setup" +description: "GPT-6.1 Terra is OpenAI's fast new model for images, computer use and writing: price, specs and how to pick it in Codex, checked 27 Oct 2026." +date: 2026-10-27 +category: concepts +categoryLabel: Concepts +type: Non-technical +primaryKeyword: "gpt-6.1 terra" +secondaryKeywords: ["gpt 6.1 terra", "gpt-6.1-terra", "gpt-6.1 terra pricing", "gpt-6.1 terra vs gpt-5.6 terra", "gpt-6.1 terra codex", "gpt 6.1"] +tags: ["Concepts", "Codex", "OpenAI", "Models"] +faq: + - q: "How much does GPT-6.1 Terra cost?" + a: "$1 per million input tokens and $5 per million output tokens on OpenAI's model page, read on 27 Oct 2026. Cached input is $0.05. Prompts over 272K input tokens cost 2x input and 1.5x output for the whole request, and Batch and Flex are 50% lower." + - q: "Is GPT-6.1 Terra cheaper than GPT-5.6 Terra?" + a: "Yes. OpenAI's model pages list GPT-5.6 Terra at $2 input and $12 output per million tokens, against $1 and $5 for GPT-6.1 Terra, both read on 27 Oct 2026." + - q: "How do I use GPT-6.1 Terra in Codex?" + a: "In the Codex CLI, version 0.159.0 or later, run codex -m gpt-6.1-terra. In the ChatGPT desktop app, open Advanced under the composer and pick it from the model list where your plan offers it, per OpenAI's Codex models page on 27 Oct 2026." + - q: "What is the GPT-6.1 Terra context window?" + a: "1,050,000 tokens, with up to 922,000 input tokens and 128,000 output tokens, and a knowledge cutoff of 1 June 2026, per OpenAI's model page read on 27 Oct 2026." +--- + +GPT-6.1 Terra is OpenAI's new fast, efficient model for visual reasoning, computer use and writing. OpenAI released it on 26 October 2026. Its API price is $1 per million input tokens and $5 per million output tokens as of 27 Oct 2026, half or less of the GPT-5.6 Terra price. + +Codex is one of the engines in [Munder Difflin](https://harnessmd.com/download), free and open source: a desktop app that runs a team of AI agents for all kinds of knowledge work, coding included, on your own computer. The [install guide](/blog/how-to-install-and-use-munder-difflin/) covers setup. New to Codex? Start with [what is Codex](/blog/what-is-codex/). + +## What is GPT-6.1 Terra? + +The third of four models in OpenAI's GPT-6 lineup, between GPT-6.1 Sol and GPT-6 Luna. OpenAI's [GPT-6 guide](https://developers.openai.com/api/docs/guides/latest-model), read on 27 Oct 2026, describes them like this: + +- **GPT-6 Astra**: "Highest intelligence". +- **GPT-6.1 Sol**: balanced speed, cost and intelligence. +- **GPT-6.1 Terra**: "Fast and efficient". +- **GPT-6 Luna**: the fastest and most cost effective. + +The guide's examples for Terra: matching product photos to catalog entries, comparing technical drawings, acting on application screens, and drafting and revising text. The [API changelog](https://developers.openai.com/api/docs/changelog) lists the release under Oct 26. The [Hacker News thread](https://news.ycombinator.com/item?id=50248124) had 215 points when we checked on 27 Oct 2026. + +
Animation. On a white background, four labelled boxes stand in a row from tall to short: Astra, Sol, Terra and Luna. The Terra box lifts slightly and a yellow tag drops onto it reading Fast and efficient, while three small icons appear beside it: a picture, a pointer arrow and a pencil.
GPT-6.1 Terra sits third in OpenAI's GPT-6 lineup, per its GPT-6 guide on 27 Oct 2026.
+ +## What does GPT-6.1 Terra cost? + +$1 per million input tokens and $5 per million output tokens, on OpenAI's [model page](https://developers.openai.com/api/docs/models/gpt-6.1-terra) read on 27 Oct 2026. Cached input is $0.05, which the page says is 5% of the input rate (27 Oct 2026). + +| Price per 1M tokens, 27 Oct 2026 | Input | Cached input | Output | +| --- | --- | --- | --- | +| GPT-6 Astra | $10 | $1 | $50 | +| GPT-6.1 Sol | $2 | $0.10 | $10 | +| **GPT-6.1 Terra** | **$1** | **$0.05** | **$5** | +| GPT-5.6 Terra | $2 | $0.20 | $12 | +| GPT-6 Luna | $0.10 | $0.01 | $0.50 | + +Five rules on the model page change the bill: + +- Prompts over 272K input tokens cost 2x the input and cache rates and 1.5x output, for the full request. +- Batch and Flex prices are 50% lower than Standard. +- Fast mode costs 2x Standard. +- Cache writes cost $1.25 per million tokens for 30 minute retention and $2.50 for 12 hour retention (27 Oct 2026). +- Regional processing adds 10% where available. + +For ChatGPT plan prices rather than API prices, see [Codex pricing](/blog/codex-pricing/). + +
Animation. A white price tag reads GPT-5.6 Terra, $2 in and $12 out. A second, smaller tag slides in front of it reading GPT-6.1 Terra, $1 in and $5 out, and a small mint label pops up beside it saying per 1M tokens.
API prices per 1 million tokens on OpenAI's model pages, read 27 Oct 2026.
+ +## What is GPT-6.1 Terra good at? + +Images, screens and text. The model page calls it "A fast, efficient model for visual reasoning, precise computer use, and clear, natural writing". It takes text and images as input and writes text; audio and video are not supported. + +Its reasoning effort has six settings, from `none` to `max`, with `medium` as the default. The guide says to start with `medium` and raise it "if the improvement in quality is worth the added time and tokens". GPT-6.1 Sol, by contrast, has no `none` setting; its lowest is `low`. + +In the Responses API, Terra can use web search, file search, image generation, code interpreter, hosted shell, apply patch, skills, computer use, MCP and tool search. Tool calling requires the Responses API, and fine tuning is not supported. + +
Animation. A round dial on a white card has six stops labelled none, low, medium, high, xhigh and max. The pointer starts at medium, which glows yellow as the default, then sweeps up to max and back to medium.
Six reasoning effort settings, medium by default, per OpenAI's model page on 27 Oct 2026.
+ +## How do you use GPT-6.1 Terra in Codex and ChatGPT? + +Pick it by name. OpenAI's [Codex models page](https://developers.openai.com/codex/models), read on 27 Oct 2026, lists it in these places: + +- **Codex CLI**, version 0.159.0 or later: run `codex -m gpt-6.1-terra`, or switch inside a session with `/model`. +- **Work and Codex in the ChatGPT desktop app**: open **Advanced** under the composer and choose it from the model list; OpenAI says the options vary by plan, workspace and rollout. +- **ChatGPT Work on the web.** +- **The API**, which the model page says supports the Responses and Chat Completions endpoints. + +The same page calls Terra "a fast, efficient choice for writing, visual understanding, and computer use". For screen work in the desktop app, see [Codex computer use](/blog/codex-computer-use/). + +## Which GPT-6 model should you pick in Codex? + +The Codex models page, read on 27 Oct 2026, starts from the kind of work: + +- **GPT-6 Astra** suits the most demanding workflows. +- **GPT-6.1 Sol** offers near Astra performance at a lower cost than Astra. +- **GPT-6.1 Terra** is the fast, efficient choice for writing, visual understanding and computer use. +- **GPT-6 Luna** suits focused, repeatable tasks. + +The page says these picks apply to ChatGPT Work and Codex. Moving from GPT-5.6 Terra? The guide says to compare both models on representative images and workflows at the same reasoning effort, and to move tool calls from Chat Completions to the Responses API. + +
Animation. A white terminal window shows the line codex -m gpt-6.1-terra being typed. A small card below it labelled Codex CLI 0.159.0 or later gets a mint tick, and the model chip on the window changes to 6.1 Terra.
The Codex CLI needs version 0.159.0 or later for GPT-6.1 Terra, per OpenAI's Codex models page on 27 Oct 2026.
+ +## GPT-6.1 Terra at a glance, checked 27 Oct 2026 + +| Spec | GPT-6.1 Terra | +| --- | --- | +| Model ID | `gpt-6.1-terra` | +| Released | 26 Oct 2026 | +| Context window | 1,050,000 tokens | +| Maximum input | 922,000 tokens | +| Maximum output | 128,000 tokens | +| Knowledge cutoff | 1 Jun 2026 | +| Input and output | Text and images in, text out | +| Price as of 27 Oct 2026 | $1 input, $5 output per 1M tokens | +| Reasoning effort | none, low, medium (default), high, xhigh, max | + + diff --git a/docs/blog/agent-tools-today-2026-10-26/index.html b/docs/blog/agent-tools-today-2026-10-26/index.html index 1091bfd564..9c9050095d 100644 --- a/docs/blog/agent-tools-today-2026-10-26/index.html +++ b/docs/blog/agent-tools-today-2026-10-26/index.html @@ -235,7 +235,7 @@

How this list is built + + + + - + -