diff --git a/_config.yml b/_config.yml index 1712ad0..f6ed45b 100644 --- a/_config.yml +++ b/_config.yml @@ -39,6 +39,7 @@ exclude: - Makefile - CLAUDE.md - .claude/ + - docs/ ############################################################ # Site configuration for the Jekyll 3 Pagination Gem diff --git a/_data/navigation.yml b/_data/navigation.yml index ace4f1d..93bde6f 100644 --- a/_data/navigation.yml +++ b/_data/navigation.yml @@ -24,6 +24,10 @@ main_menu: url: "/news" menu_type: "simple" + - text: "Status" + url: "/status.html" + menu_type: "simple" + - text: "FAQ" url: "/faq.html" menu_type: "simple" diff --git a/_data/runs.yml b/_data/runs.yml index 1968b93..e68cf68 100644 --- a/_data/runs.yml +++ b/_data/runs.yml @@ -81,6 +81,43 @@ runs: description: "Chip-on-board packaged parts shipped" status: "delivery" + # Shuttle status page stops (rendered by /status.html). + # Explicit status ("done" | "current" | "pending") always wins; without it + # the page falls back to comparing `date` against the build time. + # Run 1 had no early bird pricing, so that stop is omitted. + stops: + - title: "Final Order Date" + date: "2025-11-28" + display_date: "28 November 2025" + status: "done" + - title: "GDS In Date" + date: "2025-12-03" + display_date: "3 December 2025" + status: "done" + - title: "GF Mask Manufacturing" + date: "2026-01-08" + display_date: "January – February 2026" + status: "done" + - title: "GF Wafer Manufacturing" + date: "2026-03-03" + display_date: "March – May 2026" + status: "done" + - title: "Dicing & Sorting" + date: "2026-05-29" + display_date: "Late May 2026" + status: "done" + - title: "Bare Dies Shipped" + date: "2026-06-03" + display_date: "Early June 2026" + status: "done" + - title: "Chip on Board Packaging" + date: "2026-06-15" + display_date: "June 2026" + status: "done" + - title: "Chip on Board Packaged Shipped" + display_date: "Rolling out from June 2026" + status: "current" + gf180mcu_run_2: name: "GF180MCU Run 2" process: "GF180MCU" @@ -168,6 +205,37 @@ runs: description: "Bare dies and packaged parts shipped to customers" status: "delivery" + # Shuttle status page stops (rendered by /status.html). + # Fab stage dates are estimates: GDS in 30 June 2026 plus the ~12-week + # fab time observed on Run 1, landing on the 16 October 2026 delivery. + stops: + - title: "Early Bird Deadline" + date: "2026-04-30" + display_date: "30 April 2026" + status: "done" + - title: "Final Order Date" + date: "2026-06-30" + display_date: "30 June 2026" + status: "done" + - title: "GDS In Date" + date: "2026-07-14" + display_date: "14 July 2026" + status: "done" + - title: "GF Mask Manufacturing" + display_date: "Late July 2026" + status: "done" + - title: "GF Wafer Manufacturing" + display_date: "Est. August – October 2026" + status: "current" + - title: "Dicing & Sorting" + display_date: "Est. October 2026" + - title: "Bare Dies Shipped" + display_date: "Est. 16 October 2026" + - title: "Chip on Board Packaging" + display_date: "Est. November 2026" + - title: "Chip on Board Packaged Shipped" + display_date: "Est. November 2026" + gf180mcu_run_3: name: "GF180MCU Run 3" process: "GF180MCU" @@ -253,3 +321,33 @@ runs: display_date: "Q2 2027" description: "Bare dies and packaged parts shipped to customers" status: "delivery" + + # Shuttle status page stops (rendered by /status.html). + # Hard deadlines carry machine-readable dates so their status flips + # automatically at build time; manufacturing stages are estimates that + # get updated editorially as the run progresses. + stops: + # Deadline timestamps mirror the canonical early_bird_deadline / + # campaign_deadline / submission_deadline values above (end of day + # AoE) so a stop never shows as passed while orders are still open. + - title: "Early Bird Deadline" + date: "2026-10-01T11:59:00Z" + display_date: "30 September 2026" + - title: "Final Order Date" + date: "2026-12-10T11:59:00Z" + display_date: "9 December 2026" + - title: "GDS In Date" + date: "2026-12-17T11:59:00Z" + display_date: "16 December 2026" + - title: "GF Mask Manufacturing" + display_date: "Est. January 2027" + - title: "GF Wafer Manufacturing" + display_date: "Est. January – April 2027" + - title: "Dicing & Sorting" + display_date: "Est. April 2027" + - title: "Bare Dies Shipped" + display_date: "Est. 16 April 2027" + - title: "Chip on Board Packaging" + display_date: "Est. May 2027" + - title: "Chip on Board Packaged Shipped" + display_date: "Est. May 2027" diff --git a/_includes/components/rocket.html b/_includes/components/rocket.html new file mode 100644 index 0000000..7522ea1 --- /dev/null +++ b/_includes/components/rocket.html @@ -0,0 +1,16 @@ +{% comment %} + Inline SVG rocket for the shuttle status page (/status.html). + + Usage: {% include components/rocket.html mode="flying" %} + mode: "flying" — nose down (travelling to the next stop), flame lit + "parked" — nose up (launch pad / mission complete), flame off +{% endcomment %} + diff --git a/_posts/2026-07-24-run3-coming-soon.md b/_posts/2026-07-24-run3-coming-soon.md index f5e60bd..734e6fb 100644 --- a/_posts/2026-07-24-run3-coming-soon.md +++ b/_posts/2026-07-24-run3-coming-soon.md @@ -33,7 +33,7 @@ The tools are open source. The PDK is open source. Your design can be open or cl Run 1 has been packaged and shipped to all of our customers -- from hobbyists to academics, and from industry specialists to community groups, people have been able to get their hands on their very own custom silicon. Many are testing their designs right now, and our chip-on-board packaging solution has been popular and successful! Read more about it in -our dedicated [chip-on-board progress update](/news/chip-on-board-progress). +our dedicated [chip-on-board progress update]({{ "/news/chip-on-board-progress" | relative_url }}). Run 2 has now been closed and will begin manufacturing shortly. It features several interesting projects such as: diff --git a/assets/css/custom.css b/assets/css/custom.css index 891a71a..7648e03 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -473,3 +473,255 @@ .dark-wrapper .table-footnote { color: rgba(255, 255, 255, 0.6); } + +/* Shuttle status page (/status.html) --------------------------------------- */ +/* Colors lean on the theme's palette variables (defined in the theme's + plugins.css :root block) so the page follows any future palette change. */ + +.ws-shuttle-card { + height: 100%; + padding: 1.5rem 1.5rem 1rem; + border: 1px solid rgba(var(--rgb-gray), 0.25); + border-radius: 0.5rem; + background: var(--color-white); + box-shadow: 0 0.25rem 0.75rem rgba(var(--rgb-black), 0.05); +} + +.ws-shuttle-header { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 0.5rem 0.75rem; + margin-bottom: 1.25rem; +} + +/* nowrap + flex-wrap on the header keeps the run name on one line and + drops the badge underneath when the card is too narrow for both. */ +.ws-shuttle-name { + font-size: 1.15rem; + margin: 0; + white-space: nowrap; +} + +.ws-badge { + display: inline-block; + padding: 0.25rem 0.75rem; + border-radius: 2rem; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.05em; + text-transform: uppercase; + white-space: nowrap; + color: var(--color-white); +} + +.ws-badge--delivered { background: var(--color-green); } +.ws-badge--flight { background: var(--color-purple); } +.ws-badge--boarding { background: var(--color-blue); } +.ws-badge--soon { background: var(--color-gray); } + +/* The route: a vertical rail of stops. Dots sit in a 28px column; the + connector segment entering each stop is drawn in the stop's padding-top + area by its ::before. */ +.ws-route { + list-style: none; + margin: 0; + padding: 0; + position: relative; +} + +.ws-route li { + position: relative; + padding-left: 40px; + min-height: 28px; +} + +.ws-stop { + padding-top: 26px; +} + +.ws-route li:first-child { + padding-top: 0; +} + +/* Connector segment entering this stop (drawn in the padding-top area). */ +.ws-stop::before { + content: ""; + position: absolute; + left: 13px; + top: 0; + height: 26px; + border-left: 2px dashed rgba(var(--rgb-gray), 0.5); +} + +.ws-route li:first-child::before { + content: none; +} + +/* Segment already travelled: solid green. */ +.ws-stop.is-done::before { + border-left-style: solid; + border-left-color: var(--color-green); +} + +/* Segment the rocket is currently flying: taller, to give it airspace. */ +.ws-stop.has-rocket { + padding-top: 84px; +} + +.ws-stop.has-rocket::before { + height: 84px; + border-left-color: rgba(var(--rgb-purple), 0.6); +} + +.ws-stop-dot { + position: absolute; + left: 0; + top: auto; + width: 28px; + height: 28px; + border-radius: 50%; + border: 2px solid rgba(var(--rgb-gray), 0.5); + background: var(--color-white); + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; +} + +.ws-stop .ws-stop-dot { + margin-top: -2px; +} + +.ws-stop.is-done .ws-stop-dot { + border-color: var(--color-green); + background: var(--color-green); + color: var(--color-white); +} + +.ws-stop.is-current .ws-stop-dot { + border-color: var(--color-purple); + animation: ws-current-pulse 2s ease-in-out infinite; +} + +@keyframes ws-current-pulse { + 0%, 100% { box-shadow: 0 0 0 0 rgba(var(--rgb-purple), 0.45); } + 50% { box-shadow: 0 0 0 8px rgba(var(--rgb-purple), 0); } +} + +.ws-stop-title { + display: block; + font-weight: 600; + line-height: 1.3; + padding-top: 3px; +} + +.ws-stop-date { + display: block; + font-size: 0.85rem; + color: var(--color-gray); +} + +/* Launch pad / mission complete rows. */ +.ws-route-pad { + display: flex; + align-items: center; + gap: 0.5rem; + min-height: 40px; +} + +.ws-route-pad .ws-rocket { + position: absolute; + left: 2px; +} + +.ws-route-pad-label { + font-size: 0.85rem; + font-style: italic; + color: var(--color-gray); +} + +.ws-route-pad--landed { + padding-top: 30px; +} + +.ws-route-pad--landed::before { + content: ""; + position: absolute; + left: 13px; + top: 0; + height: 26px; + border-left: 2px solid var(--color-green); +} + +/* The rocket itself. */ +.ws-rocket { + display: inline-block; + width: 24px; + height: 36px; + line-height: 0; +} + +.ws-rocket-body { fill: var(--color-purple); } +.ws-rocket-fin { fill: var(--color-sky); } +.ws-rocket-window { fill: var(--color-white); } +.ws-rocket-flame { + fill: var(--color-orange); + transform-origin: 12px 25.5px; + animation: ws-flame-flicker 0.35s ease-in-out infinite; +} + +.ws-rocket--parked .ws-rocket-flame { + display: none; +} + +/* Flying: nose points down (towards the next stop); the wrapper span + bobs along the connector while the svg carries the rotation. */ +.ws-rocket--flying .ws-rocket-svg { + transform: rotate(180deg); +} + +.ws-stop.has-rocket .ws-rocket { + position: absolute; + left: 1px; + top: 8px; + animation: ws-rocket-fly 3.2s ease-in-out infinite; +} + +@keyframes ws-rocket-fly { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(32px); } +} + +@keyframes ws-flame-flicker { + 0%, 100% { transform: scaleY(1); opacity: 0.95; } + 50% { transform: scaleY(0.7); opacity: 0.6; } +} + +.ws-status-note { + margin-top: 1rem; +} + +/* Respect reduced-motion preferences: park all the animations. */ +@media (prefers-reduced-motion: reduce) { + .ws-stop.has-rocket .ws-rocket, + .ws-rocket-flame, + .ws-stop.is-current .ws-stop-dot { + animation: none; + } +} + +/* Dark mode. */ +[data-theme="dark"] .ws-shuttle-card { + background: #242424; + border-color: rgba(255, 255, 255, 0.12); +} + +[data-theme="dark"] .ws-stop-dot { + background: #242424; +} + +[data-theme="dark"] .ws-stop.is-done .ws-stop-dot { + background: var(--color-green); +} diff --git a/docs/superpowers/specs/2026-08-15-shuttle-status-page-design.md b/docs/superpowers/specs/2026-08-15-shuttle-status-page-design.md new file mode 100644 index 0000000..cfb2515 --- /dev/null +++ b/docs/superpowers/specs/2026-08-15-shuttle-status-page-design.md @@ -0,0 +1,120 @@ +# Shuttle Status Page — Design + +Date: 2026-08-15 +Status: Approved for implementation (autonomous session; user review happens on the PR) + +## Goal + +A public page showing the status of each of the three wafer.space shuttles +(GF180MCU Run 1, Run 2, Run 3). Each shuttle displays a series of milestone +"stops", with a small animated rocket flying between the last completed stop +and the next upcoming one. + +Requested stops (per shuttle, where applicable): + +* Early Bird Deadline +* Final Order Date +* GDS In Date +* GF Mask Manufacturing +* GF Wafer Manufacturing +* Dicing & Sorting +* Bare Dies Shipped +* Chip on Board Packaging +* Chip on Board Packaged Shipped + +## Approaches considered + +1. **Hardcode stops in the page front matter.** Simple, but duplicates dates + already stored in `_data/runs.yml`; the two would drift. +2. **Extend `_data/runs.yml` with a `stops:` list per run.** Single source of + truth. Existing consumers (`_includes/components/countdown.html`, + `_includes/pricing-2col-slot.html`) access runs by explicit key or filter on + `status == 'active' and featured`, so adding new keys and a third run is + verified safe. **← Chosen.** +3. **A new `_data/shuttle_status.yml`.** Keeps `runs.yml` untouched but splits + shuttle facts across two files. + +## Data model + +Each run in `_data/runs.yml` gains a `stops:` list: + +```yaml +stops: + - title: "Early Bird Deadline" + date: "2026-04-30" # optional, ISO 8601, machine-readable + display_date: "30 April 2026" # free text shown to visitors ("TBD", "Est. …") + status: "done" # optional: done | current | pending +``` + +* Explicit `status` always wins. If absent, the template falls back to + comparing `date` against build time (`site.time`). Explicit status is the + primary mechanism because estimated dates drift from reality (Run 1's + `timeline:` in runs.yml said dies ship 28 April 2026; the news posts show + wafers only arrived 27 May 2026). +* Run 3 was announced upstream while this feature was in progress (campaign + opened 1 August 2026), so its `stops:` use the real announced dates. Hard + deadlines carry machine-readable dates; manufacturing stages are + display-only estimates so a passed estimate never auto-flips to done. +* Run 1 omits the "Early Bird Deadline" stop — Run 1 had no early bird + pricing, and inventing a date would be fabrication. +* The existing `timeline:` keys are left untouched for compatibility. + +## Page + +New `status.html` at the repository root (URL `/status.html`), following the +`faq.html` pattern exactly: `layout: default` front matter, then +`{% include layouts/nav/nav.html %}`, `{% include layouts/header/page-title.html %}`, +then page sections. + +* Three shuttle cards: `col-lg-4` each on desktop, stacked on mobile. +* Per shuttle: name, a derived status badge, and a vertical timeline of stops. + * Badge: all stops done → "Delivered"; Final Order Date stop done → + "In Flight"; active run still taking orders → "Boarding"; anything else → + "Coming Soon". +* Each stop: a dot on a vertical rail, title, and `display_date`. Done stops + get a filled dot with a checkmark; the first not-done stop gets a highlighted + "current" treatment. +* A "Status" entry is added to `_data/navigation.yml`. + +## Rocket + +* Inline SVG rocket (self-contained, themeable, no emoji font variance), + rendered by Liquid into the connector segment between the last done stop and + the first not-done stop: + * No stops done → rocket sits at the launch pad above the first stop. + * All stops done → rocket shown "landed" at the final stop, flame off. +* Animation is pure CSS (no JS): a keyframe animation floats the rocket up and + down along its connector segment, plus a flickering exhaust flame. + `prefers-reduced-motion: reduce` disables both. +* Statuses are computed at build time. This is acceptable because statuses are + editorially controlled in `runs.yml` and the site rebuilds on every content + change. + +## Styling + +Added to `assets/css/custom.css` (the established site-override stylesheet) in +its own commented section, matching the file's existing structure. Colors use +the theme's existing palette classes where possible and degrade sensibly in +dark mode. + +## Testing / verification + +* `jekyll build` passes (baseline verified before changes). +* Rendered page screenshot-verified with Playwright (desktop + mobile widths). +* The `docs/` directory is added to Jekyll's `exclude:` list so this spec does + not become a live page on the site (where muffet would link-check it). + +## Data accuracy notes (for review) + +* Run 1 "Chip on Board Packaged Shipped" is marked *current* (in progress), + not done: the last verifiable public info (news post of 3 June 2026) says + CoB packaging was still being worked through. Crowd Supply's updates page + 403-blocks bots, so completion could not be verified. Correct in + `_data/runs.yml` if this has since finished. +* Run 2 mask/wafer manufacturing dates are estimates derived from the + submission deadline (extended to 14 July 2026) plus the ~12-week fab time + observed for Run 1, landing on the published 16 October 2026 delivery + estimate. +* Run 3 deadline stops use the announced dates (early bird 30 September 2026, + orders close 9 December 2026, GDS in 16 December 2026); its manufacturing + stages are estimates anchored to the published 16 April 2027 delivery. diff --git a/status.html b/status.html new file mode 100644 index 0000000..5463805 --- /dev/null +++ b/status.html @@ -0,0 +1,134 @@ +--- +layout: default +title: "Shuttle Status" +sub_title: "Where each wafer.space shuttle is on its journey from final orders to silicon in your hands" +meta_description: "Live status of the wafer.space GF180MCU shuttle runs — from ordering deadlines through GlobalFoundries manufacturing to parts shipped." +header_image: "/assets/images/header/mpw-one-partial-dice-top-1.jpg" +--- +{% include layouts/nav/nav.html drop_search=true alignment_class="ms-auto" %} +{% include layouts/header/page-title.html %} + +
+
+
+ {% assign now_epoch = site.time | date: "%s" | plus: 0 %} + {% for run_data in site.data.runs.runs %} + {% assign run = run_data[1] %} + {% if run.stops %} + + {% comment %} Effective status per stop: explicit status wins, + otherwise fall back to comparing the stop date with build time. + status_list is built as an array so the connector segments can + look at neighbouring stops. {% endcomment %} + {% assign status_list = "" | split: "" %} + {% assign done_count = 0 %} + {% for stop in run.stops %} + {% assign eff = stop.status %} + {% unless eff %} + {% assign eff = "pending" %} + {% if stop.date %} + {% assign stop_epoch = stop.date | date: "%s" | plus: 0 %} + {% if stop_epoch <= now_epoch %}{% assign eff = "done" %}{% endif %} + {% endif %} + {% endunless %} + {% if eff == "done" %}{% assign done_count = done_count | plus: 1 %}{% endif %} + {% assign eff_as_array = eff | split: " " %} + {% assign status_list = status_list | concat: eff_as_array %} + {% endfor %} + + {% comment %} The rocket flies in the connector segment entering the + first stop that is not done. -1 means every stop is complete. {% endcomment %} + {% assign first_active = -1 %} + {% for s in status_list %} + {% if s != "done" and first_active == -1 %} + {% assign first_active = forloop.index0 %} + {% endif %} + {% endfor %} + + {% comment %} A shuttle is "In Flight" once its doors have closed + (the Final Order Date stop is done); before that an active run + is "Boarding" and anything else is "Coming Soon". {% endcomment %} + {% assign orders_closed = false %} + {% for stop in run.stops %} + {% assign i = forloop.index0 %} + {% if stop.title contains "Final Order" and status_list[i] == "done" %} + {% assign orders_closed = true %} + {% endif %} + {% endfor %} + + {% if first_active == -1 %} + {% assign badge_label = "Delivered" %} + {% assign badge_class = "ws-badge--delivered" %} + {% elsif orders_closed %} + {% assign badge_label = "In Flight" %} + {% assign badge_class = "ws-badge--flight" %} + {% elsif run.status == "active" %} + {% assign badge_label = "Boarding" %} + {% assign badge_class = "ws-badge--boarding" %} + {% else %} + {% assign badge_label = "Coming Soon" %} + {% assign badge_class = "ws-badge--soon" %} + {% endif %} + + {% assign run_id = run.name | slugify %} +
+
+
+

{{ run.name }}

+ {{ badge_label }} +
+ +
    + {% if first_active == 0 %} +
  1. + {% include components/rocket.html mode="parked" %} + {% if badge_label == "Boarding" %}Boarding — orders open{% else %}On the launch pad{% endif %} +
  2. + {% endif %} + + {% for stop in run.stops %} + {% assign i = forloop.index0 %} + {% assign eff = status_list[i] %} + {% assign has_rocket = false %} + {% if i == first_active and i > 0 %}{% assign has_rocket = true %}{% endif %} +
  3. + {% if has_rocket %} + {% include components/rocket.html mode="flying" %} + {% endif %} + {% if eff == "done" %}{% endif %} + + {% if eff == "done" %}Completed: {% elsif eff == "current" %}In progress: {% endif %} + {{ stop.title }} + + {% if stop.display_date %}{{ stop.display_date }}{% endif %} +
  4. + {% endfor %} + + {% if first_active == -1 %} +
  5. + {% include components/rocket.html mode="parked" %} + Mission complete +
  6. + {% endif %} +
+
+
+ + {% endif %} + {% endfor %} +
+ +
+
+

+ Dates for future stops are estimates and may shift as manufacturing + progresses. For the latest news, see the + news page or ask in our + Discord. +

+
+
+
+
+ +{% include layouts/footer/footer-1.html %}