Conversation
Separate node layout (relative pin offsets) from geometry (absolute positions), replacing the single geometry calculator with a layout → geometry two-step. Switch node SVG wrapper from <g> to <svg> so child elements can use percentage dimensions. Update Display node to compute its size from config resolution and add a config settings button stub. Disable the ViewModeSwitcher play button when any input pin is unconnected. Remove redundant node/connection event listeners from the simulation trigger. Key changes covered: - Layout / LayoutSource types split out from Geometry, with nodePinOffsetById replacing absolute positions - <g> → <svg> in Node/index.tsx so Default can use width="100%" - Display/geometry.ts now scales with config.resolution and exports layout constants - New ConfigSettingButton component for Display nodes - isEachInputPinConnected utility in component.ts gating the play button - executeSimulation decoupled from raw store events in the core slice
Deploying create-cpu-c8345196-9409-4cce-afc4-389f413ad8ee with
|
| Latest commit: |
e293840
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c4f9f4d5.create-cpu-c8345196-9409-4cce-afc4-389f413ad8ee.pages.dev |
| Branch Preview URL: | https://20260606.create-cpu-c8345196-9409-4cce-afc4-389f413ad8ee.pages.dev |
- Make the display ConfigSettingButton functional: open a Popover form
to edit resolution (x/y) and persist via store.nodes.update
- Compute display node size from config inside the layout calculator
- Cache getNodePinBitWidthStatus results, invalidating on node/pin/
connection register/unregister/update events
- Switch input value bit-width init to getNodePinBitWidthStatus and
deprecate getComponentPinBitWidthStatus
- Convert InputValueKey from a tuple to a { componentPinId, timeStep }
object with a serializeInputValueKey helper
- Add a reactive useCanSimulate selector and use it to drive the
ViewModeSwitcher disabled state
- Add CONST intrinsic component with fixed-bit-width output driven by configured data, plus a dedicated renderer and layout calculator - Pass node config to intrinsic evaluate functions - Fix Display renderer pixel indexing to use row-major order directly - Remove FlipFlop debug log; log pin bit widths on fixed-width mismatch
The bit width of a pin was resolved by getComponentPinBitWidthStatus, which only knows the component pin definition. A `fixed` policy was therefore evaluated against `definition.initialConfig`, so changing the resolution of a display never changed the bit width of its Pixels pin. For the same reason aggregate and decompose could not be evaluated there at all and were special cased into a `manual` fix mode, with their widths recomputed by hand in CCNodePinStore. Split the two concerns: getComponentPinBitWidthStatus now only reports how a width is determined (`automatic` or `nodeDependent`), and getNodePinBitWidthStatus resolves it from the config of the node and the manual bit widths of its pins. The `fixed` policy is renamed to `calculated` to match, and the duplicated per-node calculations for aggregate and decompose are gone. Bit widths are cached, so CCNodeStore now emits `didUpdateConfig`, kept separate from `didUpdate` so that frequent position updates do not drop the cache. Because a width can now change after a connection was made, connections whose ends no longer agree are dropped when the config changes. Also derive whether a pin is configurable and splittable from its bit width policy instead of duplicating it on the pin attributes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Const intrinsic was merged in with the `fixed` bit width policy, which is now named `calculated`. Its output width comes from the config of the node, so it is resolved per node like the display resolution. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Const node used to render a grid of randomly generated bits, so its value could neither be read nor set. It now renders a text editor whose contents are parsed into the data of the node config on every keystroke. The text is interpreted in one of three modes, binary, hex or UTF-8, which is chosen by a toggle group and kept in the config so it survives a reload. Text that is not valid in the current mode only marks the editor as invalid and leaves the last valid data in place. Pointer events on the editor no longer reach the node, so selecting text does not drag the node, and the node is resized to fit the editor. Add the AndN and OrN intrinsics, which reduce every bit of their configurable input to a single output bit. Also apply `box-sizing: border-box` globally, which the editor relies on to fill the foreign object it is rendered into. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chelproc
marked this pull request as ready for review
September 19, 2026 05:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two refactors and the features built on top of them: the node renderer is split into a layout and a geometry step, bit widths are resolved per node instead of per component pin, and on that base the Const, AndN and OrN intrinsics, display config editing and a play-mode guard are added.
Node renderer: layout → geometry split
size+ relativenodePinOffsetById) is separated from a geometry (absoluterect+nodePinPositionById).ccComponentEditorRendererLayoutToGeometryturns one into the other with the position of the node, andgetCCComponentEditorRendererNodeGeometrycomposes the two steps.<svg>instead of a<g>, so a renderer draws in local coordinates and can use percentage sizes (width="100%"in the Default renderer). Display and Const compose the Default renderer for their frame instead of drawing their own.box-sizing: border-boxis applied globally, which the HTML embedded in aforeignObjectrelies on.Bit width resolution
getComponentPinBitWidthStatusonly knew the component pin definition, so afixedwidth was evaluated againstdefinition.initialConfigand changing the resolution of a display never changed the width of its Pixels pin. Aggregate and decompose could not be evaluated there at all and were special cased into amanualfix mode, with their widths recomputed by hand inCCNodePinStore.getComponentPinBitWidthStatusreports only how a width is determined (automaticornodeDependent), andgetNodePinBitWidthStatusresolves it from the config of the node and the bit widths manually specified for its pins. Thefixedpolicy is renamed tocalculatedto match.isBitWidthConfigurableandisSplittableare folded into theconfigurablepolicy, so the policy is the only source of truth. The hard-coded cases for aggregate, decompose and broadcast are gone: manual widths are collected per pin key (In,Out, …) and passed tocalculateBitWidth, for which intrinsic pin attributes now carry their key.CCNodePinStoreand dropped on node pin and connection changes, and on the newdidUpdateConfigevent ofCCNodeStore, which is kept separate fromdidUpdateso that frequent position updates do not drop the cache.hasCompatibleBitWidthsbacksisConnectable, connections whose ends no longer agree after a config change are dropped, and existing connections are re-validated when a new one is registered.New intrinsics
config: { mode, data }, an output whose width is calculated fromdata.length, and anevaluatethat writes the configured data to the output pin. The node renders a text editor whose contents are parsed intodataon every keystroke, in one of three modes (binary, hex, UTF-8) chosen by a toggle group and kept in the config. Text that is not valid in the current mode only marks the editor and leaves the last valid data in place.evaluatefunctions receive the config of the node as a fourth argument.Display
store.nodes.update.config.resolutionand shares its constants with the renderer.inputValuein row-major order, fixing the previously reversed pixel order.Play mode and simulation
isEachInputPinConnectedand theuseCanSimulatehook disable the play button of the ViewModeSwitcher while any input pin is unconnected.executeSimulationno longer subscribes to raw node and connection store events.{ componentPinId, timeStep }with an explicitserializeInputValueKeyinstead ofJSON.stringifyof a tuple, and an initial value takes its width from the node pin implementing the component pin.Tests
nodePin.test.tscovers bit width resolution (from a display config, propagated over a connection, summed over the manual widths of aggregate and decompose pins, broadcast, and a configurable pin missing its manual width) and the consistency of connections across a config change.Open points
TODOinconnection.ts).didRegisterinCCConnectionStorelooks upnodes.getManyByComponentId(connection.parentComponentId), which returns the instances of the parent component rather than the nodes inside it, so it is currently a no-op for the component being edited. Making it match, without guarding against re-registering from inside the handler, would recurse.foreignObjectsubtracts a hard-coded30for the output pin.