From b42f815b49cf7a133abd7fc89a09ec15fe1e3fe8 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Fri, 8 May 2026 23:06:44 -0300 Subject: [PATCH] feat(components): swap BMP280 + ATtiny85 to fritzing art MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hand-drawn SVGs in Bmp280Element.ts and Attiny85Element.ts were functional but obviously amateur next to a real Fritzing-drawn part. Both components now mount the equivalent Fritzing breadboard SVG as a public static asset (`` in the shadow DOM SVG), with pin coordinates remapped to the new artwork and pin-name labels overlaid on top so the user can still read each connector at a glance. frontend/public/component-svgs/bmp280.svg (new) Verbatim copy of third-party/fritzing-parts/svg/core/breadboard/ bmp180_breadboard.svg. The Adafruit BMP180 breakout is the mechanically identical Bosch predecessor — same I2C interface, same 4-pin pinout. Pin labels lifted from the matching .fzp. frontend/public/component-svgs/attiny85.svg (new) Verbatim copy of the Fritzing ATtiny85 DIP-8 breadboard art. Bmp280Element.ts Width 80×100 px (Fritzing aspect 28.35:35.43 ≈ 0.8:1, exact uniform scale of 2.822 px/mm). Pin coords for SDA / SCL / GND / VCC matched to the connector centres in the source SVG. Pin labels overlaid on top. Existing wired example (esp32-bmp280) re-routes automatically because the wire system reads coords by pin name from pinInfo. Attiny85Element.ts Width 160×132 px (Fritzing aspect 28.801:23.768 ≈ 1.21:1, exact uniform scale of 5.555 px/mm). The Fritzing layout puts pins on the TOP and BOTTOM edges (4 each), not LEFT and RIGHT like the older hand-drawn version. Pin coords land on clean numbers (x ∈ {20, 60, 100, 140}, y ∈ {6, 126}). Built-in LED on PB1 stays as an overlaid circle outside the chip body. Wires in the existing attiny85-* examples re-route automatically by pin name; external components positioned to the right of the chip may need a manual nudge for clean routing — but they work. frontend/src/components/simulator/BoardOnCanvas.tsx attiny85: { w: 160, h: 100 } → { w: 160, h: 132 } to match the new aspect ratio. Same width as before so the chip occupies the same horizontal slot in existing example layouts. scripts/component-overrides.json BMP280 thumbnail updated to mirror the Fritzing colour scheme (dark blue PCB, BMP180 silkscreen, four gold connector circles) so picker and canvas feel consistent. frontend/public/components-metadata.json Regenerated. docs/THIRD_PARTY.md New "Fritzing parts library" section. Both new assets are listed with their upstream paths plus the CC-BY-SA licence and link to the parts repo. Future Fritzing copies must be added there too. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/THIRD_PARTY.md | 21 +++ frontend/public/component-svgs/attiny85.svg | 97 +++++++++++ frontend/public/component-svgs/bmp280.svg | 69 ++++++++ frontend/public/components-metadata.json | 2 +- .../components/simulator/BoardOnCanvas.tsx | 2 +- .../velxio-components/Attiny85Element.ts | 155 ++++++++---------- .../velxio-components/Bmp280Element.ts | 95 ++++++----- scripts/component-overrides.json | 2 +- 8 files changed, 308 insertions(+), 135 deletions(-) create mode 100644 frontend/public/component-svgs/attiny85.svg create mode 100644 frontend/public/component-svgs/bmp280.svg diff --git a/docs/THIRD_PARTY.md b/docs/THIRD_PARTY.md index c77c7eba..3c239e03 100644 --- a/docs/THIRD_PARTY.md +++ b/docs/THIRD_PARTY.md @@ -357,6 +357,25 @@ npx tsx ../scripts/generate-component-metadata.ts Verify that the component has simulation logic registered in `PartSimulationRegistry` (files `BasicParts.ts` or `ComplexParts.ts`). Only the 16 registered components have interactive behavior. +## Fritzing parts library (CC-BY-SA) + +Velxio ships a few Fritzing-drawn breadboard SVGs as static assets for +parts that wokwi-elements does not include. The original SVGs live +under `third-party/fritzing-parts/` (vendored upstream copy from +https://github.com/fritzing/fritzing-parts) and are licensed +**Creative Commons Attribution-ShareAlike** (CC-BY-SA), which requires +attribution and that derivatives stay under the same licence. + +| Velxio asset | Fritzing source | Notes | +|---|---|---| +| `frontend/public/component-svgs/bmp280.svg` | `svg/core/breadboard/bmp180_breadboard.svg` | Adafruit BMP180 breakout art reused for the BMP280 (visually identical Bosch predecessor). | +| `frontend/public/component-svgs/attiny85.svg` | `svg/core/breadboard/ATtiny85_breadboard.svg` | DIP-8 ATtiny85, used by `Attiny85Element.ts`. | + +Each Web Component that mounts one of these assets carries an inline +attribution comment pointing back to its source. Any new asset copied +out of `third-party/fritzing-parts/` MUST be added to this table and +to the corresponding component's header comment. + ## References - [Wokwi Elements Documentation](https://elements.wokwi.com/) @@ -364,3 +383,5 @@ Verify that the component has simulation logic registered in `PartSimulationRegi - [Wokwi Simulator](https://wokwi.com) - [Lit Documentation](https://lit.dev/) — Framework used by wokwi-elements - [Web Components Guide](https://developer.mozilla.org/en-US/docs/Web/Web_Components) +- [Fritzing parts repository](https://github.com/fritzing/fritzing-parts) +- [CC-BY-SA 4.0 licence text](https://creativecommons.org/licenses/by-sa/4.0/) diff --git a/frontend/public/component-svgs/attiny85.svg b/frontend/public/component-svgs/attiny85.svg new file mode 100644 index 00000000..a2ad627b --- /dev/null +++ b/frontend/public/component-svgs/attiny85.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + attiny85 + + + + + + + + + + + + + + + + + diff --git a/frontend/public/component-svgs/bmp280.svg b/frontend/public/component-svgs/bmp280.svg new file mode 100644 index 00000000..bfa4ff49 --- /dev/null +++ b/frontend/public/component-svgs/bmp280.svg @@ -0,0 +1,69 @@ + + + + + + + BMP180_BREADBOARD_v3.svg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/components-metadata.json b/frontend/public/components-metadata.json index e34223f0..1826aa78 100644 --- a/frontend/public/components-metadata.json +++ b/frontend/public/components-metadata.json @@ -3980,7 +3980,7 @@ "category": "passive" }, { - "thumbnail": "BMP280GY-BMP280", + "thumbnail": "BMP180", "tags": [ "sensor", "i2c", diff --git a/frontend/src/components/simulator/BoardOnCanvas.tsx b/frontend/src/components/simulator/BoardOnCanvas.tsx index 0fe8c20a..d9dfab39 100644 --- a/frontend/src/components/simulator/BoardOnCanvas.tsx +++ b/frontend/src/components/simulator/BoardOnCanvas.tsx @@ -30,7 +30,7 @@ const BOARD_SIZE: Record = { 'arduino-nano-esp32': { w: 217, h: 90 }, 'xiao-esp32-c3': { w: 91, h: 117 }, 'aitewinrobot-esp32c3-supermini': { w: 90, h: 123 }, - attiny85: { w: 160, h: 100 }, + attiny85: { w: 160, h: 132 }, }; interface BoardOnCanvasProps { diff --git a/frontend/src/components/velxio-components/Attiny85Element.ts b/frontend/src/components/velxio-components/Attiny85Element.ts index 4d2ab8d9..40d1121b 100644 --- a/frontend/src/components/velxio-components/Attiny85Element.ts +++ b/frontend/src/components/velxio-components/Attiny85Element.ts @@ -1,50 +1,52 @@ /** - * ATtiny85 — Web Component (DIP-8 package, Digispark-style) + * Attiny85Element.ts — DIP-8 ATtiny85 Web Component * - * Exposes the standard `pinInfo` array used by the wire system to position - * wire endpoints on real pins instead of the component corner. + * Visual: Fritzing-drawn ATtiny85 DIP package loaded as a static asset + * from /component-svgs/attiny85.svg. Original copied verbatim from + * third-party/fritzing-parts/svg/core/breadboard/ATtiny85_breadboard.svg + * (CC-BY-SA, see THIRDPARTY_LICENSES.md). * - * Pin layout (DIP-8): - * Left side (top to bottom): PB5 (RST), PB3, PB4, GND - * Right side (top to bottom): VCC, PB2, PB1, PB0 + * Geometry note (different from the original hand-drawn version): + * The Fritzing layout puts the chip HORIZONTAL with 4 pins on the TOP + * edge and 4 pins on the BOTTOM edge — not vertical with pins on + * left/right like the older art. Existing wired examples will rewire + * automatically (the wire system reads coords by pin name from + * pinInfo) but external components positioned to the right of the + * chip may need to be moved manually for clean routing. * - * The visual layout matches the older React component - * (`Attiny85.tsx` → `Attiny85`), but here we own the DOM so wires can read - * `element.pinInfo`. The `led1` attribute mirrors the PB1 (Digispark LED) - * pin state. + * viewBox 28.801 × 23.768 mm scaled uniformly at 5.555 px/mm → 160 × 132 px. + * Pin terminal centres in the source SVG (mm), all 8 connectors: + * row x y pin label + * top 3.601 1.084 VCC (connector7) + * top 10.801 1.084 PB2 (connector6) + * top 18.000 1.084 PB1 (connector5) + * top 25.201 1.084 PB0 (connector4) + * bottom 3.601 22.687 PB5 (connector0, RST) + * bottom 10.801 22.687 PB3 (connector1) + * bottom 18.000 22.687 PB4 (connector2) + * bottom 25.201 22.687 GND (connector3) + * + * Built-in LED on PB1 (Digispark convention) is overlaid as a circle in + * the outer SVG — drives off the `led1` attribute / property like before. */ -// DIP-8 dimensions (must match BoardOnCanvas BOARD_SIZE = 160 × 100) const W = 160; -const H = 100; -const BX = 30; // chip body left -const BY = 10; // chip body top -const BW = 100; // chip body width -const BH = 80; // chip body height -const PIN_W = 28; // pin stub length +const H = 132; +const TOP_Y = 6; // CSS px — y of all four top-edge pin tips +const BOT_Y = 126; // CSS px — y of all four bottom-edge pin tips +const PIN_X = [20, 60, 100, 140] as const; -// Vertical pin centres -const PIN_STARTS_Y = [BY + 10, BY + 30, BY + 50, BY + 70]; - -const PIN_LABELS_LEFT = ['PB5', 'PB3', 'PB4', 'GND']; -const PIN_LABELS_RIGHT = ['VCC', 'PB2', 'PB1', 'PB0']; - -/** - * Pin tip coordinates (where wires must attach), in SVG pixels relative to - * the element's top-left corner. The wire system reads these via the - * `pinInfo` property on the rendered DOM element. - */ const PIN_INFO: ReadonlyArray<{ name: string; x: number; y: number; description?: string }> = [ - // Left column — pin tip = BX - PIN_W - { name: 'PB5', x: BX - PIN_W, y: PIN_STARTS_Y[0], description: 'PB5 / RST' }, - { name: 'PB3', x: BX - PIN_W, y: PIN_STARTS_Y[1] }, - { name: 'PB4', x: BX - PIN_W, y: PIN_STARTS_Y[2] }, - { name: 'GND', x: BX - PIN_W, y: PIN_STARTS_Y[3] }, - // Right column — pin tip = BX + BW + PIN_W - { name: 'VCC', x: BX + BW + PIN_W, y: PIN_STARTS_Y[0] }, - { name: 'PB2', x: BX + BW + PIN_W, y: PIN_STARTS_Y[1] }, - { name: 'PB1', x: BX + BW + PIN_W, y: PIN_STARTS_Y[2], description: 'PB1 / built-in LED' }, - { name: 'PB0', x: BX + BW + PIN_W, y: PIN_STARTS_Y[3] }, + // Top row — left to right + { name: 'VCC', x: PIN_X[0], y: TOP_Y, description: 'VCC (Pin 8)' }, + { name: 'PB2', x: PIN_X[1], y: TOP_Y, description: 'PB2 / SCK / SCL / ADC1 (Pin 7)' }, + { name: 'PB1', x: PIN_X[2], y: TOP_Y, description: 'PB1 / MISO / built-in LED (Pin 6)' }, + { name: 'PB0', x: PIN_X[3], y: TOP_Y, description: 'PB0 / MOSI / SDA / OC0A (Pin 5)' }, + // Bottom row — left to right + { name: 'PB5', x: PIN_X[0], y: BOT_Y, description: 'PB5 / RESET (Pin 1)' }, + { name: 'PB3', x: PIN_X[1], y: BOT_Y, description: 'PB3 / XTAL1 / ADC3 (Pin 2)' }, + { name: 'PB4', x: PIN_X[2], y: BOT_Y, description: 'PB4 / XTAL2 / ADC2 (Pin 3)' }, + { name: 'GND', x: PIN_X[3], y: BOT_Y, description: 'GND (Pin 4)' }, ]; class Attiny85Element extends HTMLElement { @@ -75,7 +77,6 @@ class Attiny85Element extends HTMLElement { return PIN_INFO; } - /** Property setter so React's `useEffect` path can drive the LED. */ set led1(v: boolean) { this._led1 = !!v; this.updateLed(); @@ -101,69 +102,49 @@ class Attiny85Element extends HTMLElement { private render() { if (!this.shadowRoot) return; - // Build pin stubs + labels - const leftStubs = PIN_STARTS_Y.map( - (py) => ``, - ).join(''); - const rightStubs = PIN_STARTS_Y.map( - (py) => ``, - ).join(''); - const leftLabels = PIN_LABELS_LEFT.map( - (label, i) => - `${label === 'PB5' ? 'PB5/RST' : label}`, - ).join(''); - const rightLabels = PIN_LABELS_RIGHT.map( - (label, i) => - `${label}`, - ).join(''); - - // Built-in LED on PB1 (right side, 3rd from top → PIN_STARTS_Y[2]) const ledFill = this._led1 ? '#ffee44' : '#333'; const ledStroke = this._led1 ? '#ffcc00' : '#555'; const ledFilter = this._led1 ? 'drop-shadow(0 0 4px #ffcc00)' : 'none'; + // Place the LED indicator just ABOVE the PB1 top-pin (PIN_X[2], TOP_Y), + // outside the chip body so it stays readable. + const ledX = PIN_X[2]; + const ledY = TOP_Y - 12; + this.shadowRoot.innerHTML = ` - - ${leftStubs} - ${rightStubs} + + - - - - - - - - - - - ATtiny85 - 8-bit AVR - - + - - ${leftLabels} - ${rightLabels} + + VCC + PB2 + PB1 + PB0 + + PB5 + PB3 + PB4 + GND `; } diff --git a/frontend/src/components/velxio-components/Bmp280Element.ts b/frontend/src/components/velxio-components/Bmp280Element.ts index 732fd335..0e530195 100644 --- a/frontend/src/components/velxio-components/Bmp280Element.ts +++ b/frontend/src/components/velxio-components/Bmp280Element.ts @@ -1,59 +1,64 @@ /** - * Bmp280Element.ts — Custom Web Component for the BMP280 barometric sensor. + * Bmp280Element.ts — BMP280 barometric pressure + temperature sensor * - * wokwi-elements does not include a BMP280 element, so we define one here. - * Visual: a small I2C breakout board (82 × 61 px) styled after the MPU6050 module. + * wokwi-elements does not include a BMP280, so we ship our own. The visual + * is the Fritzing-drawn BMP180 breakout (mechanically identical Bosch + * predecessor — same I2C interface, same 4-pin pinout) loaded as a static + * asset from /component-svgs/bmp280.svg. Original SVG copied verbatim from + * third-party/fritzing-parts/svg/core/breadboard/bmp180_breadboard.svg + * (CC-BY-SA, see THIRDPARTY_LICENSES.md). * - * Pins: - * VCC (left, top) — 3.3 V power - * GND (left, 2nd) — Ground - * SDA (left, 3rd) — I2C data - * SCL (left, bottom)— I2C clock + * Geometry (matches the Fritzing source): + * viewBox 28.35 × 35.43 mm, scaled uniformly at 2.822 px/mm → 80 × 100 px. + * Connector centres in the source SVG (mm): all at y=4.821, with + * SDA → x=3.375 GND → x=17.773 + * SCL → x=10.574 VCC → x=24.975 + * Maps to CSS px (x ≈ mm × 2.822): + * SDA(9.5, 13.6) GND(50.2, 13.6) + * SCL(29.8, 13.6) VCC(70.5, 13.6) + * + * Pin order/names taken from third-party/fritzing-parts/core/bmp180_breakout.fzp + * (Adafruit BMP180 breakout, variant 3). */ +const W = 80; // CSS px +const H = 100; +const PIN_Y = 13.6; // CSS px — y of all four pin tips + +const PIN_INFO = [ + { name: 'SDA', x: 9.5, y: PIN_Y, number: 1, signals: [] as Array }, + { name: 'SCL', x: 29.8, y: PIN_Y, number: 2, signals: [] as Array }, + { name: 'GND', x: 50.2, y: PIN_Y, number: 3, signals: [{ type: 'power', signal: 'GND' }] }, + { name: 'VCC', x: 70.5, y: PIN_Y, number: 4, signals: [{ type: 'power', signal: 'VCC' }] }, +]; + class Bmp280Element extends HTMLElement { - readonly pinInfo = [ - { name: 'VCC', x: 0, y: 10, number: 1, signals: [{ type: 'power', signal: 'VCC' }] }, - { name: 'GND', x: 0, y: 22, number: 2, signals: [{ type: 'power', signal: 'GND' }] }, - { name: 'SDA', x: 0, y: 34, number: 3, signals: [] }, - { name: 'SCL', x: 0, y: 46, number: 4, signals: [] }, - ]; + readonly pinInfo = PIN_INFO; constructor() { super(); this.attachShadow({ mode: 'open' }).innerHTML = ` - - - - + + + + - - - BMP280 - - - - - - - - - VCC - GND - SDA - SCL - - - - - - - - GY-BMP280 + + SDA + SCL + GND + VCC `; } } diff --git a/scripts/component-overrides.json b/scripts/component-overrides.json index 230fa291..d0fc70f7 100644 --- a/scripts/component-overrides.json +++ b/scripts/component-overrides.json @@ -1957,7 +1957,7 @@ "tagName": "velxio-bmp280", "name": "BMP280 (Pressure + Temp)", "category": "sensor", - "thumbnail": "BMP280GY-BMP280", + "thumbnail": "BMP180", "properties": [], "defaultValues": {}, "pinCount": 4,