This commit is contained in:
Bane Stojkovic
2026-11-06 10:51:34 +01:00
parent 396c150472
commit eea7d45cc9
7 changed files with 212 additions and 5 deletions
+3 -2
View File
@@ -7,7 +7,7 @@
"namePrefix" : "Board", "namePrefix" : "Board",
"description" : "Blank circuit board", "description" : "Blank circuit board",
"creationMethod" : "SINGLE_CLICK", "creationMethod" : "SINGLE_CLICK",
"notes" : [ "Use 'Explicit' value for 'Dimension Mode' when placing a new board. The single control point places the top-left corner and 'Explicit Length' and 'Explicit Width' properties determine the dimensions", "Set 'Underside Display' only if explicitly asked to. The values other than 'NONE' render the mirror image of the board in the provided direction with the offset controlled by 'Underside Offset'", "Use this board as a base of PCB, eyelet and turret boards unless asked otherwise" ], "notes" : [ "Use 'Explicit' value for 'Dimension Mode' when placing a new board. The single control point places the top-left corner and 'Explicit Length' and 'Explicit Width' properties determine the dimensions", "Set 'Underside Display' only if explicitly asked to. The values other than 'NONE' render the mirror image of the board in the provided direction with the offset controlled by 'Underside Offset'", "Use this board as a base of PCB, eyelet and turret boards unless asked otherwise", "When the board needs mounting holes, because the request asks for them or the board goes into an enclosure, also select Drill Hole and use one Drill Hole per hole" ],
"properties" : [ { "properties" : [ {
"name" : "Alpha", "name" : "Alpha",
"type" : "Percentage", "type" : "Percentage",
@@ -11466,6 +11466,7 @@
"namePrefix" : "Hole", "namePrefix" : "Hole",
"description" : "Drill hole marker for PCB, chassis or faceplate", "description" : "Drill hole marker for PCB, chassis or faceplate",
"creationMethod" : "SINGLE_CLICK", "creationMethod" : "SINGLE_CLICK",
"notes" : [ "Use for round holes: the mounting holes of a Blank Board, and the holes for jacks, pots, switches and LEDs in an Enclosure; for other openings in an Enclosure use the Rectangular, Elliptical or Polygonal Cutout", "The single control point is the centre of the hole and 'Diameter' is the drilled size, e.g. 3.2mm for an M3 mounting screw. Place mounting holes inside the board, typically one near each corner and clear of the components and traces", "A hole is not conductive and has no terminals, so nothing connects to it; on a PCB it is exported as a non-plated drill" ],
"properties" : [ { "properties" : [ {
"name" : "Alpha", "name" : "Alpha",
"type" : "Percentage", "type" : "Percentage",
@@ -11526,7 +11527,7 @@
"namePrefix" : "ENC", "namePrefix" : "ENC",
"description" : "Top panel of an enclosure or chassis, optionally with its sides unfolded", "description" : "Top panel of an enclosure or chassis, optionally with its sides unfolded",
"creationMethod" : "SINGLE_CLICK", "creationMethod" : "SINGLE_CLICK",
"notes" : [ "The two control points are opposite corners of the enclosure's top panel. With 'Height' above zero the sides are unfolded around it as an exploded view, each as tall as 'Height' and set 'Spacing' apart from it: the front against the top panel's upper edge, the back against its lower edge and, when 'Sides' is All, the left and right sides against its left and right edges. The bottom is never drawn. With 'Sides' set to None, or 'Height' at zero, it is a single flat panel of any size, such as one side of a chassis drawn on its own", "The enclosure is not conductive in the netlist: jacks, pots and lugs drawn on it are not joined through it, so chassis ground points must be connected explicitly", "A datasheet model is a Hammond enclosure part number such as 1590BB, 1550B or 1444-32, or a generic size such as 125B, and is stored as 'Value'; it sets the top panel to the enclosure's length and width, upright for pedal-sized die-cast boxes up to 125 mm long and horizontal for bigger boxes and amplifier chassis and 'Height' to its wall height. 125B is a generic size sold by several makers; its Hammond equivalent is 1590N1" ], "notes" : [ "One Enclosure draws a whole box, so use one per box rather than one per side. Also select Drill Hole for the round holes of its jacks, pots, switches and LEDs, and the Rectangular, Elliptical or Polygonal Cutout for any other openings", "Draw each hole and cutout on the panel it goes through, inside that panel's outline", "The two control points are opposite corners of the enclosure's top panel. With 'Height' above zero the sides are unfolded around it as an exploded view, each as tall as 'Height' and set 'Spacing' apart from it: the front against the top panel's upper edge, the back against its lower edge and, when 'Sides' is All, the left and right sides against its left and right edges. The bottom is never drawn. With 'Sides' set to None, or 'Height' at zero, it is a single flat panel of any size, such as one side of a chassis drawn on its own", "The enclosure is not conductive in the netlist: jacks, pots and lugs drawn on it are not joined through it, so chassis ground points must be connected explicitly", "A datasheet model is a Hammond enclosure part number such as 1590BB, 1550B or 1444-32, or a generic size such as 125B, and is stored as 'Value'; it sets the top panel to the enclosure's length and width, upright for pedal-sized die-cast boxes up to 125 mm long and horizontal for bigger boxes and amplifier chassis and 'Height' to its wall height. 125B is a generic size sold by several makers; its Hammond equivalent is 1590N1" ],
"datasheetModels" : [ "1444-10", "1444-1172", "1444-12", "1444-1372", "1444-14", "1444-15", "1444-16", "1444-17132", "1444-18", "1444-22", "1444-26", "1444-29", "1444-30", "1444-45351", "1444-542", "1444-6", "1444-6415", "1444-772", "1444-8", "1444-84515", "1444-862", "1444-9", "1444-9552", "1444-972", "1444-1053", "1444-10825", "1444-12103", "1444-12123", "1444-1273", "1444-12825", "1444-14103", "1444-1463", "1444-1573", "1444-1593", "1444-17123", "1444-17133", "1444-17143", "1444-17173", "1444-1763", "1444-1773", "1444-1783", "1444-20", "1444-24", "1444-28", "1444-32", "1444-643", "1444-753", "1444-95525", "1444-9553", "1444-17105", "1444-17134", "1444-17135", "1444-17154", "1444-17156", "1444-17174", "1444-33", "1441-10", "1441-12", "1441-14", "1441-15", "1441-16", "1441-18", "1441-20", "1441-22", "1441-24", "1441-26", "1441-28", "1441-29", "1441-30", "1441-32", "1441-33", "1441-34", "1441-36", "1441-38", "1441-40", "1441-42", "1441-6", "1441-8", "1441-9", "1550A", "1550B", "1550C", "1550D", "1550E", "1550F", "1550G", "1550H", "1550J", "1550K", "1550L", "1550M", "1550N", "1550P", "1550Q", "1590A", "1590B", "1590B2", "1590B3", "1590BB", "1590BB2", "1590BBS", "1590BS", "1590BX", "1590BX2", "1590C", "1590CE", "1590D", "1590DD", "1590DE", "1590E", "1590EE", "1590F", "1590G", "1590G2", "1590H", "1590J", "1590K", "1590KK", "1590LB", "1590LLB", "1590N1", "1590P1", "1590Q", "1590R1", "1590S", "1590T", "1590U", "1590V", "1590X", "1590XX", "1590Y", "125B" ], "datasheetModels" : [ "1444-10", "1444-1172", "1444-12", "1444-1372", "1444-14", "1444-15", "1444-16", "1444-17132", "1444-18", "1444-22", "1444-26", "1444-29", "1444-30", "1444-45351", "1444-542", "1444-6", "1444-6415", "1444-772", "1444-8", "1444-84515", "1444-862", "1444-9", "1444-9552", "1444-972", "1444-1053", "1444-10825", "1444-12103", "1444-12123", "1444-1273", "1444-12825", "1444-14103", "1444-1463", "1444-1573", "1444-1593", "1444-17123", "1444-17133", "1444-17143", "1444-17173", "1444-1763", "1444-1773", "1444-1783", "1444-20", "1444-24", "1444-28", "1444-32", "1444-643", "1444-753", "1444-95525", "1444-9553", "1444-17105", "1444-17134", "1444-17135", "1444-17154", "1444-17156", "1444-17174", "1444-33", "1441-10", "1441-12", "1441-14", "1441-15", "1441-16", "1441-18", "1441-20", "1441-22", "1441-24", "1441-26", "1441-28", "1441-29", "1441-30", "1441-32", "1441-33", "1441-34", "1441-36", "1441-38", "1441-40", "1441-42", "1441-6", "1441-8", "1441-9", "1550A", "1550B", "1550C", "1550D", "1550E", "1550F", "1550G", "1550H", "1550J", "1550K", "1550L", "1550M", "1550N", "1550P", "1550Q", "1590A", "1590B", "1590B2", "1590B3", "1590BB", "1590BB2", "1590BBS", "1590BS", "1590BX", "1590BX2", "1590C", "1590CE", "1590D", "1590DD", "1590DE", "1590E", "1590EE", "1590F", "1590G", "1590G2", "1590H", "1590J", "1590K", "1590KK", "1590LB", "1590LLB", "1590N1", "1590P1", "1590Q", "1590R1", "1590S", "1590T", "1590U", "1590V", "1590X", "1590XX", "1590Y", "125B" ],
"properties" : [ { "properties" : [ {
"name" : "Alpha", "name" : "Alpha",
+5 -3
View File
@@ -4,7 +4,7 @@
"Boards" : [ { "Boards" : [ {
"name" : "Blank Board", "name" : "Blank Board",
"className" : "boards.BlankBoard", "className" : "boards.BlankBoard",
"notes" : [ "Use this board as a base of PCB, eyelet and turret boards unless asked otherwise" ] "notes" : [ "Use this board as a base of PCB, eyelet and turret boards unless asked otherwise", "When the board needs mounting holes, because the request asks for them or the board goes into an enclosure, also select Drill Hole and use one Drill Hole per hole" ]
}, { }, {
"name" : "Breadboard", "name" : "Breadboard",
"className" : "boards.Breadboard" "className" : "boards.Breadboard"
@@ -283,13 +283,15 @@
"className" : "chassis.DialScale" "className" : "chassis.DialScale"
}, { }, {
"name" : "Drill Hole", "name" : "Drill Hole",
"className" : "electromechanical.DrillHole" "className" : "electromechanical.DrillHole",
"notes" : [ "Use for round holes: the mounting holes of a Blank Board, and the holes for jacks, pots, switches and LEDs in an Enclosure; for other openings in an Enclosure use the Rectangular, Elliptical or Polygonal Cutout" ]
}, { }, {
"name" : "Elliptical Cutout", "name" : "Elliptical Cutout",
"className" : "chassis.EllipticalCutout" "className" : "chassis.EllipticalCutout"
}, { }, {
"name" : "Enclosure", "name" : "Enclosure",
"className" : "chassis.ChassisPanel" "className" : "chassis.ChassisPanel",
"notes" : [ "One Enclosure draws a whole box, so use one per box rather than one per side. Also select Drill Hole for the round holes of its jacks, pots, switches and LEDs, and the Rectangular, Elliptical or Polygonal Cutout for any other openings" ]
}, { }, {
"name" : "Polygonal Cutout", "name" : "Polygonal Cutout",
"className" : "chassis.PolygonalCutout" "className" : "chassis.PolygonalCutout"
@@ -41,6 +41,9 @@ import org.diylc.core.annotations.EditableProperty;
@AiNote(value = "Use this board as a base of PCB, eyelet and turret boards unless asked otherwise", @AiNote(value = "Use this board as a base of PCB, eyelet and turret boards unless asked otherwise",
scope = Scope.SELECTION) scope = Scope.SELECTION)
@AiNote(value = "When the board needs mounting holes, because the request asks for them or the "
+ "board goes into an enclosure, also select Drill Hole and use one Drill Hole per hole",
scope = Scope.SELECTION)
@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic", @ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic",
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board",
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, transformer = SimpleComponentTransformer.class) bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, transformer = SimpleComponentTransformer.class)
@@ -37,12 +37,17 @@ import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
import org.diylc.core.VisibilityPolicy; import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.AiNote; import org.diylc.core.annotations.AiNote;
import org.diylc.core.annotations.AiNote.Scope;
import org.diylc.core.annotations.BomPolicy; import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size; import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
@AiNote(value = "One Enclosure draws a whole box, so use one per box rather than one per side. "
+ "Also select Drill Hole for the round holes of its jacks, pots, switches and LEDs, and the "
+ "Rectangular, Elliptical or Polygonal Cutout for any other openings", scope = Scope.SELECTION)
@AiNote("Draw each hole and cutout on the panel it goes through, inside that panel's outline")
@AiNote("The two control points are opposite corners of the enclosure's top panel. With 'Height' above zero the sides are unfolded around it as an exploded view, each as tall as 'Height' and set 'Spacing' apart from it: the front against the top panel's upper edge, the back against its lower edge and, when 'Sides' is All, the left and right sides against its left and right edges. The bottom is never drawn. With 'Sides' set to None, or 'Height' at zero, it is a single flat panel of any size, such as one side of a chassis drawn on its own") @AiNote("The two control points are opposite corners of the enclosure's top panel. With 'Height' above zero the sides are unfolded around it as an exploded view, each as tall as 'Height' and set 'Spacing' apart from it: the front against the top panel's upper edge, the back against its lower edge and, when 'Sides' is All, the left and right sides against its left and right edges. The bottom is never drawn. With 'Sides' set to None, or 'Height' at zero, it is a single flat panel of any size, such as one side of a chassis drawn on its own")
@AiNote("The enclosure is not conductive in the netlist: jacks, pots and lugs drawn on it are not joined through it, so chassis ground points must be connected explicitly") @AiNote("The enclosure is not conductive in the netlist: jacks, pots and lugs drawn on it are not joined through it, so chassis ground points must be connected explicitly")
@AiNote("A datasheet model is a Hammond enclosure part number such as 1590BB, 1550B or 1444-32, or a generic size such as 125B, and is stored as 'Value'; it sets the top panel to the enclosure's length and width, upright for pedal-sized die-cast boxes up to 125 mm long and horizontal for bigger boxes and amplifier chassis and 'Height' to its wall height. 125B is a generic size sold by several makers; its Hammond equivalent is 1590N1") @AiNote("A datasheet model is a Hammond enclosure part number such as 1590BB, 1550B or 1444-32, or a generic size such as 125B, and is stored as 'Value'; it sets the top panel to the enclosure's length and width, upright for pedal-sized die-cast boxes up to 125 mm long and horizontal for bigger boxes and amplifier chassis and 'Height' to its wall height. 125B is a generic size sold by several makers; its Hammond equivalent is 1590N1")
@@ -32,6 +32,8 @@ import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
import org.diylc.core.VisibilityPolicy; import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.AiNote;
import org.diylc.core.annotations.AiNote.Scope;
import org.diylc.core.annotations.BomPolicy; import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
@@ -43,6 +45,14 @@ import org.diylc.core.gerber.IGerberDrawingObserver;
import org.diylc.core.measures.Size; import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
@AiNote(value = "Use for round holes: the mounting holes of a Blank Board, and the holes for jacks, "
+ "pots, switches and LEDs in an Enclosure; for other openings in an Enclosure use the "
+ "Rectangular, Elliptical or Polygonal Cutout", scope = Scope.SELECTION)
@AiNote("The single control point is the centre of the hole and 'Diameter' is the drilled size, "
+ "e.g. 3.2mm for an M3 mounting screw. Place mounting holes inside the board, typically one "
+ "near each corner and clear of the components and traces")
@AiNote("A hole is not conductive and has no terminals, so nothing connects to it; on a PCB it is "
+ "exported as a non-plated drill")
@ComponentDescriptor(name = "Drill Hole", category = "Hardware", author = "Branislav Stojkovic", @ComponentDescriptor(name = "Drill Hole", category = "Hardware", author = "Branislav Stojkovic",
description = "Drill hole marker for PCB, chassis or faceplate", instanceNamePrefix = "Hole", description = "Drill hole marker for PCB, chassis or faceplate", instanceNamePrefix = "Hole",
zOrder = IDIYComponent.BOARD + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, zOrder = IDIYComponent.BOARD + 0.1, bomPolicy = BomPolicy.NEVER_SHOW,
+83
View File
@@ -0,0 +1,83 @@
# AI Select-With Companions
Declaring on a component which other component types must reach the AI together with it, so that the
AI server stops hard-coding component knowledge.
## 1. Goal
When the AI's component selector picks a type that is never used alone, the types it needs have to
be in the filtered catalog too, or the edit model cannot name them: given an Enclosure and told to
drill holes, but without Drill Hole in its catalog, it invented `chassis.DrillHole` instead of
`electromechanical.DrillHole`. A `SELECTION` `@AiNote` asks the selector to pick the companions, but
a note is advice to a cheap, low-effort call and can be missed. The guarantee has to be
deterministic, and it belongs with the component, not in the server.
## 2. Current state
- `@AiNote`s on `ChassisPanel` (Enclosure), `BlankBoard` and `DrillHole` tell the selector and the
edit model when to use Drill Hole and the cutouts and how to place them (see
[ai-component-notes.md](ai-component-notes.md) for notes in general).
- The guarantee lives in `diylc-ai-server/v1/ai/classes/CircuitContextBuilder.php` as constants and
two `if` blocks after the selection is merged:
- `ENCLOSURE_CLASS` (`chassis.ChassisPanel`) adds `ENCLOSURE_HOLE_CLASSES`: `DrillHole`,
`RectangularCutout`, `EllipticalCutout`, `PolygonalCutout`;
- `BLANK_BOARD_CLASS` (`boards.BlankBoard`) adds `DRILL_HOLE_CLASS`.
- `WIRE_CLASSES` sits beside them but is a different kind of rule: wires follow from the
construction type, not from a component, so it stays in PHP.
- The server reads `catalog_full.json` only after the selection, to filter it.
## 3. Design decisions
| # | Decision | Rationale |
| --- | --- | --- |
| D1 | A new single (not repeatable) annotation in `diylc-core/.../core/annotations`, `@AiSelectWith(Class<? extends IDIYComponent<?>>[] value)`, beside `@AiNote` | Class literals keep a rename or move compile-checked; core already knows components only through `IDIYComponent`, so the boundary holds. |
| D2 | Collected from the class and every superclass, merged without duplicates, like `collectNotes` | A base class can declare companions for all its subclasses, the same way it carries notes. |
| D3 | Published only in `catalog_full.json`, as `"selectWith": ["electromechanical.DrillHole", ...]` in `catalogClassName` form, and left out when empty | The server expands from the full catalog; the selector does not need it, and the index stays small. |
| D4 | One level: the server adds the companions of the selected types, not the companions of those | Nothing needs more today, and a single pass cannot loop. Revisit only if a chain appears. |
| D5 | The `@AiNote`s stay | `selectWith` only guarantees a type is present; the notes say why and how to use it. |
| D6 | Blank Board lists Drill Hole even though mounting holes are optional | One ~1.1K catalog entry the model may ignore is cheaper than a missing class name. |
| D7 | The server skips a companion that is not in its catalog | A catalog and server out of step must not break a request. |
## 4. Steps
1. **Annotation.** `AiSelectWith.java` in `org.diylc.core.annotations`, GPL header, `@Retention(RUNTIME)`,
`@Target(TYPE)`, Javadoc with `@author` as on `AiNote`.
2. **Components** (`diylc-library`):
- `ChassisPanel`: `@AiSelectWith({DrillHole.class, RectangularCutout.class, EllipticalCutout.class, PolygonalCutout.class})`;
- `BlankBoard`: `@AiSelectWith(DrillHole.class)`.
3. **Generator.** In `ComponentCatalogGenerator.buildFullEntry`, after the notes, put `selectWith`
from a `collectSelectWith(Class<?>)` that walks the hierarchy like `collectNotes` and maps each
class through the same conversion as `catalogClassName`.
4. **Tests** in `diylc-library/.../plugins/chatbot/service/ComponentCatalogGeneratorTest`:
- the generated Enclosure entry lists the four hole types and Blank Board lists Drill Hole;
- every `selectWith` entry of every component is itself a `className` in the catalog;
- `collectSelectWith` merges a superclass's companions, as the existing `collectNotes` tests do.
5. **Regenerate** `catalog_full.json` / `catalog_index.json` (run `ComponentCatalogGenerator` from
`diylc-swing`, `.run/ComponentCatalogGenerator.run.xml`), check `version` matches the latest
`update.xml` release, and copy both into `diylc-ai-server/v1/ai/`.
6. **Server.** In `CircuitContextBuilder::buildForEditIntent`:
- load `catalog_full.json` before the selection is merged instead of after;
- after `$selectedComponents` is assembled (selection, existing classes, wires, Blank Board for
PCB), add the `selectWith` of every selected type that is in the catalog, then `array_unique`;
- delete `ENCLOSURE_CLASS`, `BLANK_BOARD_CLASS`, `DRILL_HOLE_CLASS`, `ENCLOSURE_HOLE_CLASSES` and
the two `if` blocks; keep `WIRE_CLASSES`.
- Order matters: the Blank Board added for PCB must be in the list before the expansion runs.
7. **Docs.** `diylc-ai-server/docs/promptChatbot_flow.md` (filtered catalog paragraph) says the
companions come from `selectWith`; [ai-component-notes.md](ai-component-notes.md) §1 mentions
`@AiSelectWith` next to `Scope.SELECTION`.
Do step 6 only after the regenerated catalog is on the server: a catalog without `selectWith` and a
server without the constants would lose the guarantee.
## 5. Verify
- `mvn -q -pl diylc-library -am test` and `mvn -q -pl diylc-swing -am compile`.
- `php -l v1/ai/classes/CircuitContextBuilder.php`.
- A request that selects only the Enclosure ("put an LM386 amp in an enclosure") reaches the edit
model with Drill Hole and the three cutouts in its catalog; a PCB request carries Drill Hole.
## 6. Open
- Whether other types deserve companions. Candidates worth checking against real requests:
a board-mounted pot or jack with its hookup wire is already covered by `WIRE_CLASSES`, so look
for pairs the selector actually drops before adding any.
+103
View File
@@ -0,0 +1,103 @@
# DIYLC 6.10 is out: real parts, by part number
Hi everyone,
DIYLC 6.10 is ready to download, and it's one of the bigger updates in a while. The big theme this
time is **datasheets**: instead of setting up a transistor, an IC or a tube socket by hand, you can
now pick the actual part by its number and DIYLC fills in the rest for you. Thank you, as always,
for supporting the project. A lot of this release came straight from your requests and bug reports.
Here's what's new.
## Pick parts by their number
Many components now come with a built-in list of real parts. Open the component's submenu, pick a
part, and its pinout, pin names, size and other details are set in one go:
- **Transistors** (TO-92, TO-1, TO-126, TO-220 and TO-3): more than 250 transistors, JFETs, MOSFETs
and voltage regulators used in guitar effects, hi-fi, radio and synth projects.
- **ICs** ('DIP IC', 'SIP IC' and 'Multiwatt IC'): more than 100 chips, with their pin count,
spacing and pin names.
- **Tube Socket**: more than 180 preamp, power, rectifier, radio, space-charge and Soviet tubes.
There's also a new **UX4 base**, with the 300B, 2A3, 6A3 and 45 triodes and the 5Z3 rectifier.
- **Diodes** (plastic and glass): more than 300 rectifiers, Schottky, signal, germanium and zener
diodes, drawn at their real package size and colours. The Japanese clippers from those classic
overdrive pedals are in there too.
- **Sub-Mini Tube**: popular Western and Soviet sub-miniature tubes such as the 6021, 6111, 5840,
5672, 6N16B and 6N17B, with their leads, bulb size and lead names.
- **Resistor** and **Heat Sink Resistor**: their factory variants are now datasheets as well.
And the best part: **the AI Assistant knows these parts too**, so you can ask it to place a 2N3904,
a TL072 or a 12AX7 by name and it will set them up properly.
If there's a part you use all the time, you can now **pin it as the default**, just like a saved
variant. Pin the 2N3904, and a single click on the transistor places a 2N3904. Each component has
one default, so pinning a part replaces a pinned variant and the other way round.
## Enclosures, the whole box
'Chassis Panel' has grown up and is now called **Enclosure**. Set its 'Height' and choose which
'Sides' to unfold, and it draws an exploded view of the whole box instead of a single panel. It
also has its own datasheet, with more than 130 Hammond 1590, 1550, 1441 and 1444 enclosures and the
popular 125B size.
Enclosures, cutouts, 'Drill Hole' and 'Dial Scale' now live together in the new **Hardware**
category.
## Name your pins
- **'Pin Names'** on 'DIP IC', 'SIP IC' and 'Multiwatt IC' lets you name each pin (1OUT, 1IN-,
VCC+ and so on). The names are drawn on the component and show up in node tooltips, netlists and
AI analysis.
- **'Pin Labels'** on 'SIP IC' and 'Multiwatt IC' shows pin names or pin numbers next to the pins.
- 'Sub-Mini Tube' gets 'Pin Names', 'Pin Labels' and a new 'Thickness' property for drawing flat
bulbs.
- On 'Tube Socket', 'Electrode Labels' is now called 'Pin Names', the same as on ICs, and it also
gets the new 'Pin Labels' property.
- 'Transistor (TO-3)' now has a 'Pinout' property, plus a terminal in the mounting hole, so you can
wire the case (collector) and see it in netlists and AI analysis.
## Smaller improvements
- New transistor pinouts B-E-C, C-E-B and S-D-G, and regulator pinouts ADJ-IN-OUT, IN-OUT-GND and
IN-OUT-ADJ.
- The '+N' variant count in the component tree is now a button: click it to pick a variant or
datasheet part straight away, no right-click needed.
- 'Transistor (TO-1)' shows the little tab on the rim of the can next to pin 1, just like the real
part, so its orientation is easy to tell. The new 'Flange' property turns it off.
- Pins of transistors, 'SIP IC', 'DIP Switch' and 'Bridge Rectifier' are drawn on top of the body,
so they stay visible whatever the transparency, and pins now have the same colour on every
component.
- Building blocks placed as a single component now take their stacking order from the components
inside them.
## Bug fixes
- 'DIP IC' with 'Display Pin #s' set to 'No' numbered its pins in the wrong order in netlists and AI
analysis (pin 8 of an 8-pin IC came out as pin 5).
- 'Multiwatt IC' numbered its pins row by row instead of alternating between the two rows like the
real package.
- 'Multiwatt IC' in the Multiwatt 11 package had its leads 1.27mm apart instead of 1.7mm. Heads-up:
existing Multiwatt 11 parts will change shape when you open the project.
- The 'SIP IC' body was drawn too short when 'Pin Spacing' wasn't a multiple of 0.1 inch.
- SPICE netlists listed the pins of E-C-B transistors in the wrong order.
- 'Tube Socket' variants with electrode labels joined pins that share a label in netlists and AI
analysis, like both anodes of a 12AX7 or both heater ends. These variants are replaced by the new
datasheet.
- Chassis-mounted 'Tube Socket' with a Noval, 7-pin or Duodecar base didn't rotate its mounting
notches with the pins when you changed 'Angle'.
- 'Sub-Mini Tube' with circular leads counted the body centre as lead 1 in netlists and AI analysis,
so every real lead came out one number too high.
## Get it
You can download DIYLC 6.10 from the
[releases page](https://github.com/bancika/diy-layout-creator/releases), or just let the app's
update check take you there.
As always, if something doesn't work the way you expect, or there's a part you'd love to see in a
datasheet, let me know in the comments. Your feedback shapes every release.
Happy building!
Bane