← Commit history
README.md+101−92
@@ -1,143 +1,152 @@ # Fusion JLCPCB Export -Get a board from Fusion 360 to a **JLCPCB quote** just by asking your AI. This skill exports the-**complete manufacturing package**, the gerber ZIP, the **BOM with LCSC part numbers**, and the-**CPL pick-and-place**, from an open Fusion Electronics design, and can drive JLCPCB's quote tool to-**render the board and price it**. No CAM dialogs, no hand-built spreadsheets, no folder hunting.+Take a board from Fusion 360 all the way to a **ready-to-place JLCPCB order**, just by asking your AI.+This skill exports the complete manufacturing package (gerber ZIP, **BOM with LCSC part numbers**, and+**CPL pick-and-place**) from your open Fusion Electronics design, then **drives JLCPCB's quote tool in+your own logged-in Chrome**, all the way through the SMT assembly flow to the final review, so the only+thing left for you to do is eyeball it and click order. -Try it with a prompt like:+## One prompt does the whole thing  ```-Export the JLCPCB files for the board I have open in Fusion+Export the JLCPCB files for the board I have open in Fusion, then take it all the way+through the JLCPCB quote in my browser: upload the gerbers, BOM and pick-and-place,+choose SMT assembly, match the parts, check the placement, and stop at the final+review so I can look it over before ordering. Don't submit the order. ``` -```-Get me a JLCPCB quote for this board: gerbers, BOM, and pick-and-place,-then upload them to jlcpcb.com and show me the price-```+That single ask runs the entire sequence below and **stops at the last screen without submitting**, so you+can double-check every step (parts, placement, price) before you commit. Everything here is a **real run on+a real 4-layer board** (a BQ25792 charger), captured end to end. -```-Export the BOM with the LCSC part numbers and the CPL for SMT assembly-```--Everything below is a **real export of a real 4-layer board** (a BQ25792 charger), captured end to end.+> It runs in **your** browser, in the **background**. The AI uses your real, signed-in Chrome (via the+> Adom browser extension), so the quote is attached to your JLCPCB account and ready to order. It never+> steals focus or yanks the window in front of you, and it signs you in for you if needed. You are not+> asked to click anything by hand.  --- -## It is also a worked example of extending the Fusion bridge with NO pull request+## The full walkthrough -This skill does not change the Fusion bridge at all. It **ships its own EAGLE ULP** and runs it through-the bridge's generic [`fusion_electron_run`](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge) verb.-That is the whole point: **anyone can extend the Fusion bridge independently**, bring a ULP (or any-EAGLE/Electron command), run it through `electron_run`, and ship it as a community skill. You do not fork-the bridge, you do not wait for a maintainer to merge a PR. This skill is the reference for that pattern,-and it is linked from the bridge's page via the **community breadcrumb** trail so others can find it.+### Step 1. Gerbers go up and JLCPCB renders the board ----+> **You:** "Upload the gerbers and show me the board on JLCPCB" -## 1. Start from your board in Fusion+![JLCPCB rendering the board in your logged-in Chrome](screenshots/chrome-board-render.png) -> **You:** "Open the BQ25792 charger board and show me the 2D layout"+The AI exports the gerber ZIP (`fusion_export_gerbers`) and uploads it to JLCPCB's quote tool. JLCPCB+auto-detects the stackup (here a **4-layer board, 26.4 x 50.4 mm**), picks FR-4, and prices the bare board.+This first part even works **anonymously**, so you can get a board render and price with no login at all: -![The board open in Fusion's Electronics 2D editor](screenshots/board.png)+![The same board render done anonymously in a headless browser](screenshots/jlcpcb-render.png) -The source is a normal Fusion 360 **Electronics** design, open in the **2D PCB editor**. The Fusion bridge-finds and opens it from your Autodesk cloud (`fusion_aps_open`) and switches to the board view-(`fusion_show_2d_board`). From here, one ask produces every file JLCPCB needs.+### Step 2. Choose the PCBA (SMT assembly) option ----+> **You:** "Turn on SMT assembly, economic, top side" -## 2. Gerbers + drill: the fab files+![Enabling PCB Assembly and choosing the PCBA options](screenshots/pup-assembly.png) -> **You:** "Export the gerbers for this board"+Toggle **PCB Assembly** on and set the assembly type (Economic vs Standard), the side to populate, and the+build quantity. Hitting **Next** here is where JLCPCB requires a login, which is exactly why the AI drives+your own signed-in Chrome from this point on. -![What is inside the gerber ZIP](screenshots/gerber-zip.png)+### Step 3. Upload the BOM and the CPL -`fusion_export_gerbers` runs the **bundled JLCPCB CAM job** (it auto-detects 2 vs 4 layers) and writes a-single ZIP. For this 4-layer board that is **13 files**: four copper layers, soldermask and silkscreen and-paste on both sides, the board outline, the Excellon drill file, and the `.gbrjob` metadata. You upload this-ZIP to JLCPCB exactly as it comes out, nothing to rename or repackage.+> **You:** "Upload the BOM and pick-and-place files" -The gerbers are real and complete, here they are rendered straight from the exported files:+![Adding the BOM file and the CPL file](screenshots/chrome-bom-cpl-upload.png) -![The exported gerbers rendered to a board image](screenshots/board-render.png)+JLCPCB asks for two files: the **BOM** (what each part is) and the **CPL / pick-and-place** (where each part+goes). The AI uploads both straight from the export, then clicks **Process BOM & CPL**. ----+### Step 4. Confirm parts are available, and handle the ones that are not -## 3. JLCPCB renders the board and prices it+> **You:** "Make sure all the parts are in stock, flag anything that needs a replacement" -> **You:** "Upload that gerber ZIP to JLCPCB and show me the quote"+![JLCPCB matching each BOM line to a stocked LCSC part](screenshots/chrome-parts-matched.png) -![JLCPCB rendering the board from our gerbers, with the live quote](screenshots/jlcpcb-render.png)+JLCPCB matches every BOM line to a real, in-stock part using the **LCSC part number** carried in the BOM, no+manual searching. You see each part's stock type (Basic/Extended), unit price, and total. Parts it cannot+match (here the through-hole jumpers and mounting pads, which are not SMT-assembled) land in an **Unmatched+components** list, where you can search for a replacement, pre-order, or mark them do-not-place: -This is JLCPCB's own quote tool rendering the board **from the ZIP we just exported**. It correctly detected-a **4-layer board, 26.4 x 50.4 mm**, picked FR-4, and calculated a live price with a **Save to Cart** button.-The AI drove this in a browser for you (see **Getting a quote** below). The gerbers are valid and-manufacturable, the proof is JLCPCB drawing the exact board, both sides, with no warnings.+![Unmatched mechanical parts, with search / pre-order / do-not-place options](screenshots/chrome-parts-availability.png) ----+### Step 5. Check the placement and rotation preview -## 4. The BOM, with the LCSC part number per component+> **You:** "Show me the placement preview so I can verify rotations" -> **You:** "Export the BOM with the JLCPCB part numbers"+![Component placement and rotation preview on the board](screenshots/chrome-placement-preview.png) -![The exported BOM with LCSC part numbers](screenshots/bom.png)+This is the **Component Placements** step: JLCPCB draws every part on the board at the exact X/Y and rotation+from your CPL, so you can confirm nothing is mis-oriented before assembly. If a part is rotated wrong, you fix+it once with a `JLC_ROTATION` attribute back in Fusion (see below) and re-export.++### Step 6. The final review, ready to order (not submitted)++> **You:** "Take me to the final quote but don't place the order" -The BOM comes out in JLCPCB's expected layout, `Comment, Designator, Footprint, LCSC Part #`. The key column-is **LCSC Part #** (C844898, C77020, C21190, ...). That number is **read straight off each component**, the-exporter does not guess or look anything up, so JLCPCB knows the exact part to place. Lines without an LCSC-number (bare connectors, jumpers) come through blank, ready for you to fill or leave as place-only.+![The final Quote & Order screen with the full price breakdown](screenshots/chrome-quote-final.png)++The last screen is the full **Quote & Order** breakdown: PCB price, PCBA setup, stencil, components, SMT+assembly, build time, and the **grand total** (here $106.57), with a **Save to Cart** button. The AI **stops+right here without clicking it**, so you review the whole order (parts, placement, price) and place it+yourself when you are happy.  --- -## 5. The CPL pick-and-place+## What gets exported (the files behind all of the above) -> **You:** "Export the pick-and-place file"+### The gerber ZIP -![The exported CPL pick-and-place](screenshots/cpl.png)+![What is inside the gerber ZIP](screenshots/gerber-zip.png) -The CPL (Component Placement List) is `Designator, Mid X, Mid Y, Layer, Rotation`, the X/Y position, side, and-rotation of every placed part. This is what the assembler's machine reads to put each component down. Pair it-with the BOM and JLCPCB can quote **full SMT assembly**, not just the bare board.+`fusion_export_gerbers` runs the bundled JLCPCB CAM job (auto 2 vs 4 layer) and writes one ZIP with every+layer JLCPCB needs: copper, soldermask, silkscreen, paste, outline, Excellon drill, and the `.gbrjob`. ----+### The BOM, with the LCSC part number per component -## 6. Where the part numbers come from: component Attributes+![The exported BOM with LCSC part numbers](screenshots/bom.png) -> **You:** "How do I set the LCSC number so it shows up in the BOM?"+The BOM is `Comment, Designator, Footprint, LCSC Part #`. The **LCSC Part #** is read straight off each+component (no lookup), which is what lets Step 4 match every part automatically. -![Defining LCSC and JLC_ROTATION as component attributes](screenshots/attributes.png)+### The CPL pick-and-place -The magic in section 4 is set up **once, in Fusion**. JLCPCB needs to know which exact part goes on each-footprint and how it is rotated, so you add that as two component **attributes**:+![The exported CPL pick-and-place](screenshots/cpl.png) -- **`LCSC`** (required for assembly): the JLCPCB part number, e.g. `C2987638`. Find it in JLCPCB's parts-  library. The exporter reads this into the BOM's **LCSC Part #** column.-- **`JLC_ROTATION`** (only when needed): a rotation nudge in degrees for parts that land mis-oriented on the-  assembler. The exporter applies it in the CPL's **Rotation** column.+The CPL is `Designator, Mid X, Mid Y, Layer, Rotation`, the position, side, and rotation of every part, which+is what feeds the placement preview in Step 5. -Set them by right-clicking a component in the 2D board (or in the library), opening **Properties**, and adding-the name/value pairs in the **Attributes** section. The same pattern gives you a **`MPN`**, **`MOUSER`**, or-**`DIGIKEY`** attribute, so the same board can quote at any house, not just JLCPCB. Set the attribute once in-your library and every board that uses the part inherits it.+### Where the part numbers come from: component Attributes++![Defining LCSC and JLC_ROTATION as component attributes](screenshots/attributes.png)++You set this up once in Fusion. Add an **`LCSC`** attribute (the JLCPCB part number) and, only where a part+lands mis-rotated, a **`JLC_ROTATION`** attribute, on each component via right-click, Properties, Attributes.+The exporter reads them into the BOM and CPL. The same pattern gives you **`MPN`**, **`MOUSER`**, or+**`DIGIKEY`** attributes, so one board can quote at any house.  --- -## Getting a quote: three ways to drive JLCPCB, and the one we recommend+## How the browser automation works (and why it needs almost nothing from you) -The export half above is the same no matter what. To actually **upload to jlcpcb.com and get a price**, there-are three paths. The AI picks the right one for your setup.+- It drives **your real Chrome** through the [Adom browser extension](https://wiki.adom.inc/adom/adom-browser-extension)+  (CDP), so you are already signed in to JLCPCB and the quote is on your account.+- It runs in the **background**: it never forces the window to the front or steals your focus while you work.+- It **signs you in for you** if you are logged out (including Google sign-in), so you are never asked to do+  a step by hand.+- The anonymous board-render in Step 1 uses a headless cloud browser instead, handy for a quick price with no+  login. -| Path | How it works | When |-| --- | --- | --- |-| **C. Native browser (recommended)** | The AI opens **your own Chrome/Edge** (`desktop_open_url`), where you are **already signed in to JLCPCB**, and drives the page with Adom Desktop's UIA verbs (`desktop_ui_*`) plus `desktop_click`/`desktop_type` for the file picker. Screenshots each step. | You want a real, signed-in quote you can push to checkout. **This is the default.** |-| **B. Anonymous (pup)** | The AI uploads the gerber ZIP into an anonymous cloud Chromium and JLCPCB renders + prices the **bare board** (no login needed). | Quick board-only price, or a render preview, with no sign-in. (This is how the render in section 3 was captured.) |-| **A. Browser extension** | Install [`adom-browser-extension`](https://wiki.adom.inc/adom/adom-browser-extension) for full CDP control of your real browser. | Only if you want deeper browser automation; **Path C already covers the quote flow via UIA, so this is usually unnecessary.** |+---++## It is also a worked example of extending the Fusion bridge with NO pull request -**Recommendation: Path C.** It uses the browser you already have logged in, so you get a genuine,-account-attached quote and can carry it straight to checkout, and Adom Desktop's UIA verbs drive the page-without stealing focus. You only need the browser extension (Path A) if you want browser automation beyond-this flow. The anonymous path (B) is perfect for a fast board-only price or a render check.+This skill does not modify the Fusion bridge. It **ships its own EAGLE ULP** and runs it through the bridge's+generic [`fusion_electron_run`](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge) verb. That is the whole+point: anyone can extend the bridge independently, bring a ULP, run it through `electron_run`, ship it as a+community skill, no fork and no PR. It is linked from the bridge's page via the community breadcrumb trail.  --- @@ -147,11 +156,11 @@ this flow. The anonymous path (B) is perfect for a fast board-only price or a re adompkg install adom/fusion-jlcpcb-export ``` -This drops the skill plus its `jlcpcb_smta_exporter.ulp` into `~/.claude/skills/`. You also need the-[Adom Desktop Fusion 360 bridge](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge) connected, with your-board open in Fusion's 2D Electronics editor.+You also need the [Adom Desktop Fusion 360 bridge](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge)+connected with your board open, and (for the live quote) the+[Adom browser extension](https://wiki.adom.inc/adom/adom-browser-extension) in your Chrome.  ## Credits -The BOM/CPL exporter is built on OXullo Intersecans' MIT-licensed `jlcpcb_smta_exporter.ulp`. The gerber CAM-job and `fusion_electron_run` come from the Adom Desktop Fusion bridge.+BOM/CPL exporter built on OXullo Intersecans' MIT-licensed `jlcpcb_smta_exporter.ulp`. Gerber CAM job and+`fusion_electron_run` from the Adom Desktop Fusion bridge.
SKILL.md+54−31
@@ -67,50 +67,73 @@ adom-desktop pull_file '{"filePaths":["C:/tmp/jlc/<board>_bom.csv","C:/tmp/jlc/<  The gerber ZIP + the BOM + the CPL are everything JLCPCB needs. Next, get the quote. -## Getting the quote (drive jlcpcb.com)+## Getting the quote (drive jlcpcb.com all the way to the final review) -Three pathways. **Default to Path C** (the user's signed-in browser). Use Path B for a fast,-no-login board render or price check. Remember the user's preferred path once they pick one.+The user said "take it through the quote": drive **their own logged-in Chrome** through the whole SMT+assembly flow and **STOP at the final Quote & Order screen without clicking Save to Cart / submitting**,+so they can review parts, placement, and price before ordering. -### Path C, RECOMMENDED: the user's native browser (signed in, can checkout)+### Hard rules (the user was emphatic about these) -The user is already logged in to JLCPCB in their daily browser, so use it, no credentials change hands.+- **Drive everything yourself, including login. NEVER ask the user to click, log in, or "drive+  manually."** If they are logged out, sign them in (see Login below). Asking them to do a step you can+  do is exactly what they do not want.+- **Keep the browser window in the BACKGROUND.** Never `desktop_bring_to_front`. CDP eval, CDP+  screenshots, and `desktop_screenshot_window` all work on a background window, so you never steal focus+  or interrupt their other work.+- **Never submit the order.** Stop at the final review.++### Drive the real Chrome over CDP (the proven path)++The user's real Chrome runs the `adom-browser-extension` (CDP bridge, verbs `nbrowser_*`), so they are+already signed in to JLCPCB and the quote lands on their account.  ```bash-# open the quote tool in the user's own browser-adom-desktop desktop_open_url '{"url":"https://cart.jlcpcb.com/quote","browser":"default"}'-# drive the page with UIA (no focus steal): find the upload control + advance the flow-adom-desktop desktop_find_control '{"nameContains":"Add gerber"}'   # then desktop_ui_click-# the file picker is a NATIVE OS dialog, only SendInput reaches it:-adom-desktop desktop_type '{"text":"C:/tmp/jlc/<board>_gerbers.zip"}'   # then desktop_click Open-adom-desktop desktop_screenshot_window '{"hwnd":<browser hwnd>}'        # screenshot each step+adom-desktop nbrowser_status '{}'                                           # confirm ext connected+adom-desktop nbrowser_open_tab '{"url":"https://cart.jlcpcb.com/quote"}'    # opens a DEDICATED tab; returns tabId+# everything else is nbrowser_eval against that tabId (runs JS in the page, NO focus change):+adom-desktop nbrowser_eval '{"tabId":"<id>","expr":"<js>"}'+adom-desktop nbrowser_screenshot '{"tabId":"<id>"}'                        # page screenshot (base64), background+adom-desktop desktop_screenshot_window '{"hwnd":<chrome hwnd>}'            # FULL window (with chrome), background ``` -Step through: upload gerbers, let JLCPCB render, enable **PCB Assembly**, upload the **BOM** then the-**CPL**, confirm parts placement, read the price. Screenshot every step.+**Upload any file via DataTransfer** (no OS file picker needed). Base64 the file, stream it into the page+in <40k chunks (CLI arg cap), then set the input: -### Path B: anonymous cloud browser (pup), no login, board-only+```js+// per chunk (comma-op = ONE expression, which nbrowser_eval requires):+(window.__b += "<chunk>", window.__b.length)+// then build a File and set it on the right input[type=file]:+(function(){var s=atob(window.__b),u=new Uint8Array(s.length);for(var i=0;i<s.length;i++)u[i]=s.charCodeAt(i);+var f=new File([u],"name.ext",{type:"..."});var inp=document.querySelectorAll('input[type=file]')[IDX];+var dt=new DataTransfer();dt.items.add(f);inp.files=dt.files;inp.dispatchEvent(new Event('change',{bubbles:true}));})()+``` -Great for a quick render/price with zero disruption. JLCPCB renders gerbers without an account. The pup-browser is sandboxed from the local file input, so inject the ZIP bytes and set the input directly:+### The full step sequence -```bash-adom-desktop browser_open_window '{"sessionId":"jlc","url":"https://cart.jlcpcb.com/quote"}'-# base64 the ZIP and stream it into the page in <40k chunks (CLI arg-size limit):-#   (window.__gb += "<chunk>", window.__gb.length)   # comma-op = single expression-# then decode to a File and set the file input via DataTransfer:-adom-desktop browser_eval '{"sessionId":"jlc","expr":"(function(){var b=atob(window.__gb),u=new Uint8Array(b.length);for(var i=0;i<b.length;i++)u[i]=b.charCodeAt(i);var f=new File([u],\"board_gerbers.zip\",{type:\"application/zip\"});var inp=document.querySelector(\"input[type=file]\");var dt=new DataTransfer();dt.items.add(f);inp.files=dt.files;inp.dispatchEvent(new Event(\"change\",{bubbles:true}));return inp.files[0].name})()"}'-adom-desktop browser_screenshot '{"sessionId":"jlc"}'   # JLCPCB renders the board + price-```+1. **Gerbers**: inject the gerber ZIP onto the file input. JLCPCB renders + detects layers/size.+2. **PCB Assembly**: click `.switch-btn` inside the `.switch-box` to toggle assembly on; click **Next**.+3. **Login if needed**: if Next lands on `passport.jlcpcb.com/.../login`, sign them in yourself. Click the+   "Sign in with Google" button, then on `accounts.google.com` (CDP eval works there too) click their+   account row, then the OAuth **Continue** button. It redirects back logged in; the uploaded board persists.+   This is one-time; afterwards every run is fully background. Pick the user's primary work Google account.+4. **BOM + CPL**: on the SMT order page click **Next** to reveal **Add BOM File** / **Add CPL File** (two+   file inputs). Inject the BOM CSV on input[0], the CPL CSV on input[1]. Click **Process BOM & CPL**.+   (The inputs clear after the change event, that is normal; JLCPCB already read them.)+5. **Parts availability**: JLCPCB matches each BOM line to a stocked LCSC part. Through-hole jumpers /+   mounting pads (no LCSC) appear under **Unmatched components**, that is expected, they are not SMT+   assembled. Click **Next**: a dialog warns "below parts won't be assembled... Continue", click+   **Continue** to proceed (do NOT re-upload).+6. **Component Placements**: JLCPCB draws every part at its CPL X/Y + rotation. Click **Next**.+7. **Quote & Order**: the final price breakdown with **Save to Cart**. **STOP here. Do not click it.** -This is exactly how the render in the wiki page was captured: JLCPCB detected the 4-layer board, its-dimensions, and priced it, all anonymously.+Screenshot each step with `desktop_screenshot_window {hwnd}` (full window, shows it is the user's Chrome). -### Path A: browser extension+### Quick anonymous price (no login) -Only if the user wants deeper browser automation than UIA gives. Install-`adom-browser-extension` for full CDP control of their real browser. Path C already covers the quote-flow, so this is usually unnecessary, do not push it.+For just a board render + bare-board price with zero setup, do step 1 in a headless pup browser+(`browser_open_window` + `browser_eval` with the same DataTransfer trick + `browser_screenshot`). JLCPCB+renders gerbers anonymously; assembly (steps 2+) needs login, so use the real Chrome for the full quote.  ## Why the LCSC numbers are already there (no lookup) 
package.json+20−5
@@ -4,11 +4,20 @@   "type": "skill",   "title": "Fusion JLCPCB Export",   "brief": "Export the complete JLCPCB manufacturing package (gerbers + BOM with LCSC + CPL) from a Fusion board, by asking your AI.",-  "version": "1.1.0",+  "version": "1.2.0",   "description": "Export everything JLCPCB needs to quote and assemble a board, gerber ZIP plus the BOM (with the LCSC part numbers) and the CPL pick-and-place, straight from a Fusion 360 Electronics design via the Adom Desktop Fusion bridge. Ships its own EAGLE ULP and runs it through the bridge's generic electron_run, a working example of extending the Fusion bridge independently (no fork, no pull request).",   "org": "adom",   "dependencies": {},-  "tags": ["fusion360", "jlcpcb", "lcsc", "bom", "cpl", "gerber", "manufacturing", "pcb"],+  "tags": [+    "fusion360",+    "jlcpcb",+    "lcsc",+    "bom",+    "cpl",+    "gerber",+    "manufacturing",+    "pcb"+  ],   "discovery_triggers": [     "export for jlcpcb",     "jlcpcb bom cpl",@@ -22,6 +31,12 @@     "jlcpcb smt assembly export",     "export the bom with part numbers"   ],-  "scripts": { "install": "./install.sh", "uninstall": "./uninstall.sh" },-  "hero": { "type": "image", "path": "screenshots/hero.png" }-}+  "scripts": {+    "install": "./install.sh",+    "uninstall": "./uninstall.sh"+  },+  "hero": {+    "type": "image",+    "path": "screenshots/hero.png"+  }+}\ No newline at end of file
page.json+1−1
@@ -4,7 +4,7 @@   "type": "skill",   "title": "Fusion JLCPCB Export",   "brief": "Export the complete JLCPCB manufacturing package (gerbers + BOM with LCSC + CPL) from a Fusion board, by asking your AI.",-  "version": "1.1.0",+  "version": "1.2.0",   "description": "Export everything JLCPCB needs to quote and assemble a board, gerber ZIP plus the BOM (with the LCSC part numbers) and the CPL pick-and-place, straight from a Fusion 360 Electronics design via the Adom Desktop Fusion bridge. Ships its own EAGLE ULP and runs it through the bridge's generic electron_run, a working example of extending the Fusion bridge independently (no fork, no pull request).",   "org": "adom",   "dependencies": {},
screenshots/chrome-board-render.pngadded
⋯ 1 unchanged line ⋯
screenshots/chrome-bom-cpl-upload.pngadded
⋯ 1 unchanged line ⋯
screenshots/chrome-parts-availability.pngadded
⋯ 1 unchanged line ⋯
screenshots/chrome-parts-matched.pngadded
⋯ 1 unchanged line ⋯
screenshots/chrome-placement-preview.pngadded
⋯ 1 unchanged line ⋯
screenshots/chrome-quote-final.pngadded
⋯ 1 unchanged line ⋯
screenshots/pup-assembly.pngadded
⋯ 1 unchanged line ⋯