Project Overview: React for PCBs
tscircuit offers a unique approach to printed circuit board (PCB) design by leveraging React. Developers describe hardware components using familiar React syntax, like <resistor name="R1" footprint="0805" />. The tscircuit/core renderer then translates these descriptions into actual manufacturing outputs, including component placement, copper traces, silkscreen details, netlists, and Gerber files. This core renderer is central to the entire process; any placement bug within it would propagate to every board exported by any user.
The discovery of this particular bug was not through code inspection but during the practical process of building an LED matrix board. This real-world application highlights how subtle rendering issues can surface only when components are actively being laid out, underscoring the importance of testing beyond synthetic benchmarks.
The Discovery: Misaligned Components
The issue manifested when a user was attempting to lay out an LED matrix. While using the pcbLayout={{ matchAdapt: true }} prop, intended to align components based on their footprints, the renderer began to stack components unnaturally. Instead of distributing components across the board as expected, the bug caused multiple components to be placed directly on top of each other, all originating from the same point (0,0) on the PCB coordinate system.
This behavior is particularly insidious because it doesn't necessarily crash the renderer or produce an obvious error message. The output files, such as Gerbers, would appear valid on the surface, but upon closer inspection or manufacturing, it would become clear that components were not placed correctly. The visual effect is that of components being 'glued' together at the origin, making the design unusable.
The matchAdapt: true prop is designed to facilitate automated component placement by matching them to predefined footprints and ensuring proper alignment. When this prop functions correctly, it significantly speeds up the design process for repetitive structures like LED matrices or component arrays. However, when it fails, as it did in this instance, it leads to catastrophic placement errors that affect the entire board.
Root Cause: Off-by-One in Coordinate Transformation
The bug was traced to an off-by-one error within the coordinate transformation logic in the tscircuit/core renderer. Specifically, the issue lay in how the renderer calculated and applied the placement offsets for components when the matchAdapt: true prop was enabled. The renderer was failing to correctly account for the cumulative offsets required to position each subsequent component relative to the previous one or a designated origin.
Instead of calculating distinct positions for each component, the faulty logic resulted in the placement offset being reset or incorrectly applied for every component, effectively telling each new component to occupy the same origin space as the first. This is akin to a drawing program where each new shape is told to draw at coordinate (0,0) instead of being offset from the previous one. The result is a single point containing all the geometry, not a spread-out layout.
The problem was exacerbated by the fact that the renderer processed components sequentially. The first component might be placed correctly relative to the board's origin. However, subsequent components, intended to be placed relative to the first or at calculated distances, were all being assigned the same or a very similar origin-based coordinate. This behavior silently corrupted the placement data without throwing an exception, making it difficult to debug without direct visual inspection of the rendered output or the final Gerber files.
The Fix: Correct Offset Accumulation
The fix involved correcting the coordinate transformation algorithm to ensure that offsets are properly accumulated and applied for each component. The developers adjusted the logic to maintain a running total of positional adjustments, ensuring that each component is placed at its intended unique location on the PCB. This involved meticulously reviewing the calculation of translation vectors and ensuring they were correctly applied in the rendering pipeline.
The corrected code now accurately calculates the position for each component, taking into account its footprint dimensions and its relation to other components or the board's origin. This ensures that when matchAdapt: true is used, components are spread out correctly according to their footprints and design rules, rather than being piled up at a single point.
The fix was implemented as part of the DEV's Summer Bug Smash event, a community-driven initiative aimed at identifying and resolving bugs. This collaborative environment often brings fresh perspectives to complex issues, as demonstrated by the bug's discovery during practical use rather than through static code analysis.
Broader Implications for PCB Design Software
This bug in tscircuit/core highlights a critical challenge in declarative hardware design tools: the potential for subtle, cascading errors. When a core rendering or layout engine has a fundamental flaw, it impacts every design produced by that tool. The silence of the bug—producing seemingly valid output that is functionally incorrect—makes it particularly dangerous, as it could go unnoticed until manufacturing, leading to significant delays and costs.
For developers of PCB design software, this case emphasizes the need for robust validation at multiple stages. This includes not only syntax checking of the declarative code but also geometric validation of the rendered output. Tools should ideally include checks for overlapping components, impossibly dense placements, or components outside the defined board boundaries, especially when automated layout props are used.
The discovery method also serves as a reminder that real-world usage is the ultimate test. While unit tests and static analysis are crucial, bugs that only appear under specific, complex layout conditions can be missed. Encouraging community bug reporting and building tools that make it easy for users to submit reproducible examples of faulty output are vital for improving the reliability of these sophisticated design tools.
What's Next for tscircuit
With the core rendering bug fixed, tscircuit can move forward with greater confidence. Users can now leverage the layout features, including matchAdapt: true, knowing that component placement will be handled correctly. The incident underscores the project's commitment to stability and its responsiveness to community feedback, especially through events like the Bug Smash.
The ongoing development of tscircuit aims to make PCB design as intuitive as front-end web development. By abstracting away much of the complexity of traditional EDA (Electronic Design Automation) tools, it lowers the barrier to entry for developers who are more comfortable with code than complex graphical interfaces. This bug fix ensures that the foundation of this abstraction is sound, paving the way for more advanced features and broader adoption.
