PageSourceSearch

https://asic42.ok.kimi.link/js/charts/timeline42.js

js asic42.ok.kimi.link collected 2026-10-03 04:51:14 UTC 15,888 bytes, 272 lines download raw bytes

1// 四十二年一线 · 1985–2026 事件墙图 · SVG(timeline66 的 42 年口径版)
2// 六个窗口色带垫底(当前窗口蓝、其余墨灰,窄带标签上下交错),事件牌匾贪心分层
3// 错峰排布(层数决定图高),连杆落轴,逐块 L→R draw-in,每块可点下钻。
4// 牌匾事实全部可在 RPT.analog_matrix / tm_tables / archive 页与 V52 中找到对应行;
5// 无源者(1987 TSMC 创立、2016 cohort 成立年)按「宁缺勿编」不绘。
6(() => {
7  const host = document.getElementById("timeline42-chart");
8  if (!host) return;
9  const body = U.frame(host, {
10    title: "Forty-two years on one line",
11    sub: "shaded = the six windows · blue = current window · red = a break · click any plaque",
12    src: "Kimi Research",
13  });
14
15  const P = U.PAL;
16  const MONO = U.FONTS.mono;
17  const SERIF = U.FONTS.serif;
18  const NS = "http://www.w3.org/2000/svg";
19  const svgEl = (n, a) => { const e = document.createElementNS(NS, n); for (const k in a) e.setAttribute(k, a[k]); return e; };
20
21  // kind: ink=历史事件(墨色)/ brk=崩盘·下行(语义红)/ cur=当前周期事件(电蓝)
22  // drill 数值+口径+带日期出处,全部对应到数据行
23  const PLAQUES = [
24    { y: 1984, yr: "1983–84", name: "Xilinx and Altera founded", kind: "ink",
25      drill: { title: "1983–84 · Xilinx and Altera founded",
26        value: "Altera 1983-06 · Xilinx 1984-02",
27        sub: "Altera's first round $1.3M; Xilinx's $4.3M (Dataquest 1987 archive). Both independently chose not to build fabs — the fabless model starts here.",
28        source: "Kimi Research" } },
29    { y: 1994, yr: "1994", name: "Xilinx takes the PLD crown", kind: "ink",
30      drill: { title: "1994 · the PLD crown changes hands",
31        value: "Xilinx takes the PLD crown (1994)",
32        sub: "Xilinx: 1990 IPO, FY1996 $560M. AMD's PLD unit lost the crown in 1994 and was sold to Vantis → Lattice in 1999.",
33        source: "Kimi Research" } },
34    { y: 2000, yr: "2000", name: "Telecom bubble peaks", kind: "ink",
35      drill: { title: "2000 · telecom bubble peaks",
36        value: "Nasdaq peaks 2000-03; the order freeze arrives 9–12 months later",
37        sub: "Xilinx FY2001 10-K: 'Net revenue growth slowed substantially in the fourth quarter of fiscal 2001 due to decelerating bookings and order cancellations' — particularly in the telecommunications sector.",
38        source: "Company disclosure" } },
39    { y: 2001, yr: "2001", name: "Industry −32% · duopoly −39%", kind: "brk",
40      drill: { title: "2001 · the clearing",
41        value: "Industry −32% · both duopolists −39%",
42        sub: "WSTS cut its full-year forecast to −32% (Oct 2001); double-ordering in the shortage became mountains of inventory in the downturn. The reference scale for this report's downside stress tests.",
43        source: "Company disclosure" } },
44    { y: 2003, yr: "2003", name: "The $12 million-gate FPGA", kind: "ink",
45      drill: { title: "2003 · the $12 million-gate FPGA",
46        value: "Spartan-3: a million-gate FPGA priced under $12",
47        sub: "Two quarters after climbing out of the −32% trough, Xilinx's CEO declared an assault on the $23B ASIC/ASSP market — weaponizing the cost curve.",
48        source: "Company disclosure" } },
49    { y: 2012, yr: "2012", name: "Microsoft wires 1,632 FPGA servers", kind: "ink",
50      drill: { title: "2012 · the invisible deployment",
51        value: "1,632 FPGA servers wired by end-2012",
52        sub: "Microsoft Project Catapult: each server = Xeon + PCIe daughter card (Stratix V). Not public at the time; disclosed at ISCA 2014 — per-server ranking throughput +95% at a fixed latency distribution.",
53        source: "Kimi Research" } },
54    { y: 2015, yr: "2015", name: "Google deploys TPU v1", kind: "ink",
55      drill: { title: "2015 · Google deploys TPU v1",
56        value: "In production 2015 · disclosed 2016-05 · ISCA 2017",
57        sub: "65,536 8-bit MACs; 92 TOPS peak (INT8); 28MiB on-chip; vs Haswell/K80 avg 15–30x performance, 30–80x efficiency. Inference only.",
58        source: "Kimi Research" } },
59    { y: 2016, yr: "2016", name: "Intel buys into AI", kind: "ink",
60      drill: { title: "2016 · Intel buys into AI",
61        value: "Nervana + Movidius · ≈$400M / undisclosed",
62        sub: "The 2015–18 acquisition chain: Altera $16.7B (2015), Nervana/Movidius (2016), Mobileye $15.3B (2017). Nervana was killed in 2019; Movidius kept at the edge.",
63        source: "Kimi Research" } },
64    { y: 2020, yr: "2020", name: "AMD bids $35B for Xilinx", kind: "ink",
65      drill: { title: "2020 · the M&A supercycle",
66        value: "AMD bids $35B for Xilinx (all stock, 2020-10-27)",
67        sub: "China conditional approval 2022-01-27; completed 2022-02-14 at ≈$49B — the largest semiconductor deal in history. NVIDIA → Arm ($40B) was terminated the same week.",
68        source: "Kimi Research" } },
69    { y: 2022, yr: "2022", name: "Oct 7: peak meets controls", kind: "brk",
70      drill: { title: "2022 · peak meets controls",
71        value: "BIS final rule 2022-10-07; 2022H2 PC −19.5% triggered the reversal",
72        sub: "A100/H100 effectively banned for China; equipment limits at 14/16nm FinFET, 18nm DRAM, 128-layer NAND; the 'US persons' clause introduced for the first time. The two markets now cycle separately.",
73        source: "Industry & official" } },
74    { y: 2023, yr: "2023", name: "Generative AI ignites", kind: "cur",
75      drill: { title: "2023 · generative AI ignites",
76        value: "The inference window opens",
77        sub: "Demand trigger of the current window: generative-AI inference. By 2024-02 NVIDIA's CFO put ≈40% of the past year's data-center revenue on inference.",
78        source: "Company disclosure" } },
79    { y: 2025, yr: "2025", name: "NVLink Fusion opens the platform", kind: "cur",
80      drill: { title: "2025 · NVLink Fusion opens the platform",
81        value: "Third-party XPUs onto NVLink scale-up (official, 2025-05-18)",
82        sub: "Third-party CPU/XPU onto NVLink, NVLink Switch, bridge chiplet/IP, mixed NVIDIA-GPU clusters. Launch partners: MediaTek, Marvell, Alchip, Astera Labs, Synopsys, Cadence; GUC on the ecosystem page.",
83        source: "Company disclosure" } },
84    { y: 2026, yr: "2026", name: "Expansion confirmed · no peak yet", kind: "cur", dashed: true,
85      drill: { title: "2026 · expansion confirmed",
86        value: "No peak yet — NVIDIA data-center +92% (2026Q1)",
87        sub: "CoWoS capacity on the 70→120→200 kwpm track (2025A → 2026E → 2027E capacity); the constraint is moving forward to power and datacenter shells.",
88        source: "Kimi Research" } },
89  ];
90
91  // 六个窗口 = analog_matrix 的 1985–2026 各行(1960–84 行超出 42 年口径,不绘)
92  const WINDOWS = [
93    { id: "W1", y0: 1985, y1: 1995, name: "FPGA founding" },
94    { id: "W2", y0: 1995, y1: 2003, name: "telecom bubble" },
95    { id: "W3", y0: 2004, y1: 2012, name: "the quiet decade" },
96    { id: "W4", y0: 2013, y1: 2018, name: "ignition" },
97    { id: "W5", y0: 2019, y1: 2022, name: "first in-house wave" },
98    { id: "W6", y0: 2023, y1: 2026, name: "inference boom", cur: true },
99  ];
100
101  // ── 尺寸 ──
102  const PH = 46, TIER_GAP = 12, TIER_H = PH + TIER_GAP, TOP = 20, AXIS_GAP = 12;
103  const X0 = 1983.5, X1 = 2026.8, ML = 26, MR = 26, GAP = 10;
104  const COL = { ink: P.ink, brk: P.neg, cur: P.blue };
105
106  const mc = document.createElement("canvas").getContext("2d");
107  const nameW = s => { mc.font = "700 12px " + SERIF; return mc.measureText(s).width; };
108
109  let played = false; // 入场动画是否已播完(resize/字体回退后保持完成帧)
110
111  function build(final) {
112    body.innerHTML = "";
113    const W = Math.min(1120, Math.max(620, body.getBoundingClientRect().width || host.getBoundingClientRect().width - 20));
114    const xOf = yr => ML + (yr - X0) / (X1 - X0) * (W - ML - MR);
115
116    // ── 贪心分层:按年份升序,放进不叠压的最低层 ──
117    const ps = PLAQUES.map((p, i) => ({ ...p, i, w: Math.max(96, Math.ceil(nameW(p.name)) + 20) }));
118    const tiers = []; // tiers[t] = 该层最右占用边
119    ps.forEach(p => {
120      p.x = U.clamp(xOf(p.y) - p.w / 2, ML, W - MR - p.w);
121      let t = 0;
122      while (t < tiers.length && p.x < tiers[t] + GAP) t++;
123      p.tier = t; tiers[t] = p.x + p.w;
124      p.leadX = U.clamp(xOf(p.y), p.x + 12, p.x + p.w - 12);
125    });
126    const nTiers = tiers.length;
127    const axisY = TOP + nTiers * TIER_H + AXIS_GAP;
128    const H = axisY + 66;
129
130    const svg = svgEl("svg", { width: "100%", height: H, viewBox: `0 0 ${W} ${H}`,
131      style: "display:block", "data-drill-keep": "1", class: "t42-svg" });
132    body.appendChild(svg);
133    const yOf = t => TOP + (nTiers - 1 - t) * TIER_H; // 层 0 贴近轴,层数越高越靠上
134
135    const animated = []; // { start, dur, set(p) }
136
137    // ── 窗口色带(轴下切段,窄带标签上下交错)──
138    const segY = axisY + 7, segH = 5;
139    WINDOWS.forEach((w, i) => {
140      const x0 = xOf(w.y0) + 1, x1 = xOf(Math.min(w.y1, X1)) - 1;
141      const seg = svgEl("rect", { x: x0, y: segY, height: segH, rx: 1,
142        fill: w.cur ? "rgba(34,81,255,.22)" : "rgba(133,149,166,.18)" });
143      svg.appendChild(seg);
144      animated.push({ start: 0.05 + i * 0.05, dur: 0.45, set: p => { seg.setAttribute("width", Math.max(0, (x1 - x0) * p)); } });
145
146      const lc = U.clamp((x0 + x1) / 2, ML + 34, W - MR - 34);
147      const row = i % 2; // 上下交错
148      const ty = axisY + (row ? 46 : 24);
149      const l1 = svgEl("text", { x: lc, y: ty, "text-anchor": "middle",
150        style: `font:9px ${MONO};fill:${w.cur ? P.blue : P.inkMd}` });
151      l1.textContent = `${w.id} · ${w.y0}–${String(w.y1).slice(2)}`;
152      const l2 = svgEl("text", { x: lc, y: ty + 11, "text-anchor": "middle",
153        style: `font:8.5px ${MONO};fill:${w.cur ? P.blue : P.inkLo}` });
154      l2.textContent = w.name;
155      [l1, l2].forEach(t => { svg.appendChild(t); animated.push({ start: 0.4 + i * 0.05, dur: 0.4, set: p => { t.setAttribute("opacity", p); } }); });
156    });
157
158    // ── 年代刻度 + 淡格线 ──
159    [1990, 2000, 2010, 2020].forEach(yr => {
160      const px = xOf(yr);
161      const gl = svgEl("line", { x1: px, y1: TOP - 6, x2: px, y2: axisY, stroke: P.lineLo, "stroke-width": 1 });
162      svg.appendChild(gl);
163      const tk = svgEl("line", { x1: px, y1: axisY - 4, x2: px, y2: axisY + 4, stroke: P.inkLo, "stroke-width": 1 });
164      const lb = svgEl("text", { x: px, y: axisY - 8, "text-anchor": "middle",
165        style: `font:9px ${MONO};fill:${P.inkLo}` });
166      lb.textContent = yr;
167      svg.appendChild(tk); svg.appendChild(lb);
168      [gl, tk, lb].forEach(e => { e.setAttribute("opacity", 0); animated.push({ start: 0.25, dur: 0.5, set: p => { e.setAttribute("opacity", p); } }); });
169    });
170
171    // ── 主轴(L→R 画出)──
172    const ax = svgEl("line", { x1: xOf(X0), y1: axisY, y2: axisY, stroke: P.ink, "stroke-width": 1.2 });
173    svg.appendChild(ax);
174    animated.push({ start: 0, dur: 0.7, set: p => { ax.setAttribute("x2", xOf(X0) + (xOf(X1) - xOf(X0)) * p); } });
175    [xOf(X0), xOf(X1)].forEach(px => {
176      const e = svgEl("line", { x1: px, y1: axisY - 4, x2: px, y2: axisY + 4, stroke: P.ink, "stroke-width": 1.2 });
177      svg.appendChild(e); e.setAttribute("opacity", 0);
178      animated.push({ start: 0.5, dur: 0.3, set: p => { e.setAttribute("opacity", p); } });
179    });
180
181    // 连杆层垫底(穿牌时隐于牌匾之后),落轴圆点层次之,牌匾最上
182    const leadLayer = svgEl("g", { class: "t42-leaders" });
183    const dotLayer = svgEl("g", { class: "t42-dots" });
184    svg.appendChild(leadLayer); svg.appendChild(dotLayer);
185
186    // ── 牌匾:hairline 描边 + mono 年份眉标 + 粗体墨字事件名 ──
187    ps.forEach(p => {
188      const S = 0.55 + p.i * 0.11; // 逐块错峰(按年份 L→R)
189      const c = COL[p.kind], py = yOf(p.tier);
190      const g = svgEl("g", { class: "t42-plaque", style: "cursor:pointer" });
191      svg.appendChild(g);
192
193      // 连杆(落轴)
194      const lead = svgEl("line", { x1: p.leadX, x2: p.leadX, y1: py + PH, y2: py + PH,
195        stroke: p.kind === "brk" ? "rgba(194,47,78,.45)" : p.kind === "cur" ? "rgba(34,81,255,.45)" : "rgba(5,28,44,.3)",
196        "stroke-width": 1 });
197      leadLayer.appendChild(lead);
198      animated.push({ start: S + 0.25, dur: 0.35, set: q => {
199        lead.setAttribute("y2", py + PH + (axisY - py - PH) * q); lead.setAttribute("opacity", q);
200      } });
201
202      // 落轴圆点:当前窗口实心蓝,其余空心
203      const dot = svgEl("circle", { cx: p.leadX, cy: axisY, r: 0,
204        fill: p.kind === "cur" ? P.blue : P.paper,
205        stroke: p.kind === "cur" ? P.blue : p.kind === "brk" ? P.neg : P.inkMd, "stroke-width": 1.2 });
206      dotLayer.appendChild(dot);
207      animated.push({ start: S + 0.55, dur: 0.2, set: q => { dot.setAttribute("r", 3 * q); } });
208
209      // 框(draw-in:描边沿周长画出;2026 完成后切虚线)
210      const rect = svgEl("rect", { x: p.x, y: py, width: p.w, height: PH, fill: P.paper,
211        stroke: c, "stroke-width": 1 });
212      g.appendChild(rect);
213      const per = 2 * (p.w + PH);
214      rect.setAttribute("stroke-dasharray", per);
215      animated.push({ start: S, dur: 0.45, set: q => {
216        rect.setAttribute("stroke-dashoffset", per * (1 - q));
217        if (q >= 1 && p.dashed) rect.setAttribute("stroke-dasharray", "4 3");
218      } });
219
220      const ey = svgEl("text", { x: p.x + 10, y: py + 15, style: `font:9px ${MONO};fill:${c};opacity:.8` });
221      ey.textContent = p.yr;
222      const idx = svgEl("text", { x: p.x + p.w - 10, y: py + 15, "text-anchor": "end",
223        style: `font:8px ${MONO};fill:${P.inkLo}` });
224      idx.textContent = String(p.i + 1).padStart(2, "0");
225      const nm = svgEl("text", { x: p.x + 10, y: py + 34, style: `font:700 12px ${SERIF};fill:${c}` });
226      nm.textContent = p.name;
227      [ey, idx, nm].forEach(t => { g.appendChild(t); t.setAttribute("opacity", 0);
228        animated.push({ start: S + 0.28, dur: 0.3, set: q => { t.setAttribute("opacity", q); } }); });
229
230      // ── 点击下钻 ──
231      g.addEventListener("click", e => {
232        U.showDrill({ title: p.drill.title, value: p.drill.value, sub: p.drill.sub,
233          source: p.drill.source, x: e.clientX, y: e.clientY });
234      });
235    });
236
237    // ── 入场动画(reduced-motion → 直接完成帧)──
238    if (final || matchMedia("(prefers-reduced-motion: reduce)").matches) {
239      animated.forEach(a => a.set(1));
240      played = true;
241      return;
242    }
243    animated.forEach(a => a.set(0));
244    let running = false, t0 = null;
245    const total = Math.max(...animated.map(a => a.start + a.dur)) + 0.05;
246    function tick(ts) {
247      if (t0 == null) t0 = ts;
248      const el = (ts - t0) / 1000;
249      animated.forEach(a => a.set(U.smooth(U.clamp((el - a.start) / a.dur, 0, 1))));
250      if (el < total && running) requestAnimationFrame(tick);
251      else { running = false; played = true; animated.forEach(a => a.set(1)); }
252    }
253    function start() { if (running || played) return; running = true; t0 = null; requestAnimationFrame(tick); }
254    const io = new IntersectionObserver(es => {
255      if (!es[0].isIntersecting) return;
256      io.disconnect(); start();
257    }, { threshold: 0.15 });
258    io.observe(svg);
259  }
260
261  build(false);
262  // 字体就位后若牌匾宽度变了则重排(保持完成帧,不重播动画)
263  if (document.fonts && document.fonts.ready) {
264    const before = PLAQUES.map(p => nameW(p.name));
265    document.fonts.ready.then(() => {
266      const changed = PLAQUES.some((p, i) => Math.abs(nameW(p.name) - before[i]) > 2);
267      if (changed) build(true);
268    });
269  }
270  let rt;
271  window.addEventListener("resize", () => { clearTimeout(rt); rt = setTimeout(() => build(true), 200); });
272})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.