2026-07-02 14:48:11 +02:00
|
|
|
/*
|
|
|
|
|
* Embind dispatcher for the merged kicad_editor WASM image (editor-unification Part 2).
|
|
|
|
|
*
|
|
|
|
|
* The pcbnew and eeschema binding TUs each implement the collab bridge for their own
|
|
|
|
|
* frame and, standalone, register the SAME JS-facing names. In the merged image both
|
|
|
|
|
* TUs are compiled with -DKICAD_MERGED_EMBIND, which
|
|
|
|
|
* - compiles out their duplicate frame-agnostic definitions (kicadOpenFile,
|
|
|
|
|
* extern "C" kicadCollabOnSave) — the single definitions live HERE, and
|
|
|
|
|
* - compiles out their shared-name EMSCRIPTEN_BINDINGS registrations — registered
|
|
|
|
|
* once HERE, dispatching to the renamed per-editor entries (pcbCollab… and
|
|
|
|
|
* schCollab…) on whichever editor frame is live. Per-editor unique names
|
|
|
|
|
* (kicadSaveBoard, kicadSaveSchematic, kicadCollabTestItemBlob, Board_…) keep
|
|
|
|
|
* flowing from the per-editor blocks unchanged.
|
|
|
|
|
*
|
|
|
|
|
* With the one-frame-per-page-load model exactly one of pcbEditorActive() /
|
|
|
|
|
* schEditorActive() is true — the same dynamic_cast probe every per-editor entry
|
|
|
|
|
* already starts with. JS-facing names and signatures are IDENTICAL to the standalone
|
|
|
|
|
* bundles, so the web app and tests need no per-bundle API differences.
|
|
|
|
|
*
|
|
|
|
|
* Deliberately header-light: no pcbnew/eeschema headers (avoids mixing both include
|
|
|
|
|
* roots in one TU); only the generic KIWAY_PLAYER surface + the extern declarations.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
|
#include <emscripten.h>
|
|
|
|
|
#include <emscripten/bind.h>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <wx/app.h>
|
|
|
|
|
#include <wx/string.h>
|
|
|
|
|
#include <wx/window.h>
|
|
|
|
|
#include <kiway.h>
|
|
|
|
|
#include <kiway_player.h>
|
|
|
|
|
|
|
|
|
|
using namespace emscripten;
|
|
|
|
|
|
|
|
|
|
// Per-editor entry points and frame probes — defined (with external linkage) in
|
|
|
|
|
// pcbnew_embind.cpp / eeschema_embind.cpp.
|
|
|
|
|
bool pcbEditorActive();
|
|
|
|
|
void pcbCollabApply( std::string aJson );
|
|
|
|
|
void pcbCollabApplyItems( std::string aJson );
|
|
|
|
|
std::string pcbCollabSnapshot();
|
|
|
|
|
std::string pcbCollabSnapshotItems();
|
|
|
|
|
std::string pcbCollabTestMoveFirst( int aDx, int aDy );
|
|
|
|
|
std::string pcbCollabGetPos( std::string aId );
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
bool pcbCollabTestRemoveItem( std::string aId );
|
|
|
|
|
bool pcbCollabTestRotateItem( std::string aId, double aDeg );
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
// Presence (collab-presence 0002) + comment pins/panning (0005).
|
2026-07-06 15:59:51 +02:00
|
|
|
void pcbCollabPresenceStart();
|
|
|
|
|
void pcbCollabSetRemote( std::string aJson );
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
void pcbCollabSetPins( std::string aJson );
|
|
|
|
|
void pcbCollabSetViewport( double aCx, double aCy );
|
feat(collab): dev-time presence style tuner (VITE_PRESENCE_TUNER=1)
Parametrizes every visual knob of the presence overlay so we can pick the
shipped look live, then wire the winners into the defaults:
- collab_presence_style.h: shared STYLE struct + drawing (now used by BOTH
editor TUs — no more duplicated overlay code): selection shape (rect /
corner brackets / underline / rounded rect / filled-only), border width +
alpha, infill alpha, padding, corner radius; name tag show/size/chip-
background/inside-outside/top-bottom/start-end-center/offset; cursor shape
(cross / pointer / circle+dot), size/width/alpha + label knobs; fixed-color
and palette-by-name-hash overrides (try palettes without changing what
senders publish); pin radius/ring/alphas. Defaults == shipped look.
- kicadCollabSetStyle(json) live-patch export + kicadCollabTestListItems(n)
(real KIIDs for synthetic previews); merged dispatch; pins now carry the
author name so palette overrides recolor them consistently.
- PresenceTuner.tsx: floating dev panel (env-gated, tree-shaken otherwise) —
grouped sliders/selects, demo peers+pins injection for SOLO tuning,
localStorage persistence across reloads, Copy JSON export, reset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 19:10:40 +02:00
|
|
|
void pcbCollabSetStyle( std::string aJson );
|
|
|
|
|
std::string pcbCollabTestListItems( int aCount );
|
feat(collab): tuner round 2 — center-anchored labels, exact outlines, varied demo set, clearer color modes
- collab_presence_style.h: GAL BitmapText CENTERS on its position (confirmed
in GAL::ResetTextAttributes — the mispositioned nameplates); labels/chips
now hand GAL the block center. New selection shape 5 'exact outline':
pcbnew hugs real geometry (footprint bounding hull, TransformShapeToPolygon
for the rest, padding inflates the polygon); eeschema falls back to rect.
- kicadCollabTestDemoSet (both TUs + merged): labeled demo groups — smallest
+ largest footprint and the two busiest nets' segments (symbols + wire
bundles on sch) — so the style preview covers the real range of shapes.
- PresenceTuner: Colors section rebuilt as explicit modes (per-user / fixed /
palette) with preset palettes (default, pastel, vivid, okabe-ito), buffered
hex editing + Apply (the old always-filtering textarea ate keystrokes), an
'overlay only' hint; demo injection consumes the varied demo set; 'exact
outline (pcb)' in the shape list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-07 10:41:15 +02:00
|
|
|
std::string pcbCollabTestDemoSet();
|
2026-07-06 15:59:51 +02:00
|
|
|
std::string pcbCollabGetViewport();
|
|
|
|
|
std::string pcbCollabGetSelection();
|
|
|
|
|
std::string pcbCollabTestSelectFirst();
|
|
|
|
|
bool pcbCollabTestClearSelection();
|
2026-07-02 14:48:11 +02:00
|
|
|
|
|
|
|
|
bool schEditorActive();
|
|
|
|
|
void schCollabApply( std::string aJson );
|
|
|
|
|
void schCollabApplyItems( std::string aJson );
|
|
|
|
|
std::string schCollabSnapshot();
|
|
|
|
|
std::string schCollabSnapshotItems();
|
|
|
|
|
std::string schCollabTestMoveFirst( int aDx, int aDy );
|
|
|
|
|
std::string schCollabGetPos( std::string aId );
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
bool schCollabTestRemoveItem( std::string aId );
|
|
|
|
|
bool schCollabTestRotateItem( std::string aId, double aDeg );
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
// Presence (collab-presence 0003 — eeschema counterparts) + pins (0005).
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
void schCollabPresenceStart();
|
|
|
|
|
void schCollabSetRemote( std::string aJson );
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
void schCollabSetPins( std::string aJson );
|
|
|
|
|
void schCollabSetViewport( double aCx, double aCy );
|
feat(collab): dev-time presence style tuner (VITE_PRESENCE_TUNER=1)
Parametrizes every visual knob of the presence overlay so we can pick the
shipped look live, then wire the winners into the defaults:
- collab_presence_style.h: shared STYLE struct + drawing (now used by BOTH
editor TUs — no more duplicated overlay code): selection shape (rect /
corner brackets / underline / rounded rect / filled-only), border width +
alpha, infill alpha, padding, corner radius; name tag show/size/chip-
background/inside-outside/top-bottom/start-end-center/offset; cursor shape
(cross / pointer / circle+dot), size/width/alpha + label knobs; fixed-color
and palette-by-name-hash overrides (try palettes without changing what
senders publish); pin radius/ring/alphas. Defaults == shipped look.
- kicadCollabSetStyle(json) live-patch export + kicadCollabTestListItems(n)
(real KIIDs for synthetic previews); merged dispatch; pins now carry the
author name so palette overrides recolor them consistently.
- PresenceTuner.tsx: floating dev panel (env-gated, tree-shaken otherwise) —
grouped sliders/selects, demo peers+pins injection for SOLO tuning,
localStorage persistence across reloads, Copy JSON export, reset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 19:10:40 +02:00
|
|
|
void schCollabSetStyle( std::string aJson );
|
|
|
|
|
std::string schCollabTestListItems( int aCount );
|
feat(collab): tuner round 2 — center-anchored labels, exact outlines, varied demo set, clearer color modes
- collab_presence_style.h: GAL BitmapText CENTERS on its position (confirmed
in GAL::ResetTextAttributes — the mispositioned nameplates); labels/chips
now hand GAL the block center. New selection shape 5 'exact outline':
pcbnew hugs real geometry (footprint bounding hull, TransformShapeToPolygon
for the rest, padding inflates the polygon); eeschema falls back to rect.
- kicadCollabTestDemoSet (both TUs + merged): labeled demo groups — smallest
+ largest footprint and the two busiest nets' segments (symbols + wire
bundles on sch) — so the style preview covers the real range of shapes.
- PresenceTuner: Colors section rebuilt as explicit modes (per-user / fixed /
palette) with preset palettes (default, pastel, vivid, okabe-ito), buffered
hex editing + Apply (the old always-filtering textarea ate keystrokes), an
'overlay only' hint; demo injection consumes the varied demo set; 'exact
outline (pcb)' in the shape list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-07 10:41:15 +02:00
|
|
|
std::string schCollabTestDemoSet();
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
std::string schCollabGetViewport();
|
|
|
|
|
std::string schCollabGetSelection();
|
|
|
|
|
std::string schCollabTestSelectFirst();
|
|
|
|
|
bool schCollabTestClearSelection();
|
2026-07-02 14:48:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Programmatically open a project file in the running editor frame, without UI
|
|
|
|
|
// automation. Frame-agnostic (any KIWAY_PLAYER); byte-identical to the definition the
|
|
|
|
|
// standalone bundles compile from their own binding TU.
|
|
|
|
|
static bool kicadOpenFile( std::string path )
|
|
|
|
|
{
|
|
|
|
|
KIWAY_PLAYER* frame =
|
|
|
|
|
wxTheApp ? static_cast<KIWAY_PLAYER*>( wxTheApp->GetTopWindow() ) : nullptr;
|
|
|
|
|
|
|
|
|
|
if( !frame )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if( wxWindow* blocking = frame->Kiway().GetBlockingDialog() )
|
|
|
|
|
blocking->Close( true );
|
|
|
|
|
|
|
|
|
|
return frame->OpenProjectFiles(
|
|
|
|
|
std::vector<wxString>( 1, wxString::FromUTF8( path.c_str() ) ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// C++ → JS save notification. Called from BOTH fork save chokepoints
|
|
|
|
|
// (PCB_EDIT_FRAME::SavePcbFile and SCH_EDIT_FRAME::saveSchematicFile) — one shared
|
|
|
|
|
// definition serves the merged image. No-op without a JS listener.
|
|
|
|
|
extern "C" void kicadCollabOnSave( const char* aPath )
|
|
|
|
|
{
|
|
|
|
|
EM_ASM( {
|
|
|
|
|
if( window.kicadCollab && window.kicadCollab.onSave )
|
|
|
|
|
window.kicadCollab.onSave( UTF8ToString( $0 ) );
|
|
|
|
|
}, aPath );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dispatch shims: route each shared JS name to the live editor's implementation.
|
|
|
|
|
// The sch path is the fallback arm so a JS call with NO frame up behaves like the
|
|
|
|
|
// standalone bundles (the per-editor impls no-op / return empty on a null frame).
|
|
|
|
|
static void collabApply( std::string aJson )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabApply( aJson ) : schCollabApply( aJson );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void collabApplyItems( std::string aJson )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabApplyItems( aJson ) : schCollabApplyItems( aJson );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabSnapshot()
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabSnapshot() : schCollabSnapshot();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabSnapshotItems()
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabSnapshotItems() : schCollabSnapshotItems();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabTestMoveFirst( int aDx, int aDy )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestMoveFirst( aDx, aDy )
|
|
|
|
|
: schCollabTestMoveFirst( aDx, aDy );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabGetPos( std::string aId )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabGetPos( aId ) : schCollabGetPos( aId );
|
|
|
|
|
}
|
|
|
|
|
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
static bool collabTestRemoveItem( std::string aId )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestRemoveItem( aId ) : schCollabTestRemoveItem( aId );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool collabTestRotateItem( std::string aId, double aDeg )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestRotateItem( aId, aDeg )
|
|
|
|
|
: schCollabTestRotateItem( aId, aDeg );
|
|
|
|
|
}
|
|
|
|
|
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
// Presence shims (collab-presence 0002 pcbnew / 0003 eeschema): route to the live
|
|
|
|
|
// editor's implementation, same pattern as the collab bridge shims above.
|
2026-07-06 15:59:51 +02:00
|
|
|
static void collabPresenceStart()
|
|
|
|
|
{
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
pcbEditorActive() ? pcbCollabPresenceStart() : schCollabPresenceStart();
|
2026-07-06 15:59:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void collabSetRemote( std::string aJson )
|
|
|
|
|
{
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
pcbEditorActive() ? pcbCollabSetRemote( aJson ) : schCollabSetRemote( aJson );
|
2026-07-06 15:59:51 +02:00
|
|
|
}
|
|
|
|
|
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
static void collabSetPins( std::string aJson )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabSetPins( aJson ) : schCollabSetPins( aJson );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void collabSetViewport( double aCx, double aCy )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabSetViewport( aCx, aCy ) : schCollabSetViewport( aCx, aCy );
|
|
|
|
|
}
|
|
|
|
|
|
feat(collab): dev-time presence style tuner (VITE_PRESENCE_TUNER=1)
Parametrizes every visual knob of the presence overlay so we can pick the
shipped look live, then wire the winners into the defaults:
- collab_presence_style.h: shared STYLE struct + drawing (now used by BOTH
editor TUs — no more duplicated overlay code): selection shape (rect /
corner brackets / underline / rounded rect / filled-only), border width +
alpha, infill alpha, padding, corner radius; name tag show/size/chip-
background/inside-outside/top-bottom/start-end-center/offset; cursor shape
(cross / pointer / circle+dot), size/width/alpha + label knobs; fixed-color
and palette-by-name-hash overrides (try palettes without changing what
senders publish); pin radius/ring/alphas. Defaults == shipped look.
- kicadCollabSetStyle(json) live-patch export + kicadCollabTestListItems(n)
(real KIIDs for synthetic previews); merged dispatch; pins now carry the
author name so palette overrides recolor them consistently.
- PresenceTuner.tsx: floating dev panel (env-gated, tree-shaken otherwise) —
grouped sliders/selects, demo peers+pins injection for SOLO tuning,
localStorage persistence across reloads, Copy JSON export, reset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 19:10:40 +02:00
|
|
|
static void collabSetStyle( std::string aJson )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabSetStyle( aJson ) : schCollabSetStyle( aJson );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabTestListItems( int aCount )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestListItems( aCount ) : schCollabTestListItems( aCount );
|
|
|
|
|
}
|
|
|
|
|
|
feat(collab): tuner round 2 — center-anchored labels, exact outlines, varied demo set, clearer color modes
- collab_presence_style.h: GAL BitmapText CENTERS on its position (confirmed
in GAL::ResetTextAttributes — the mispositioned nameplates); labels/chips
now hand GAL the block center. New selection shape 5 'exact outline':
pcbnew hugs real geometry (footprint bounding hull, TransformShapeToPolygon
for the rest, padding inflates the polygon); eeschema falls back to rect.
- kicadCollabTestDemoSet (both TUs + merged): labeled demo groups — smallest
+ largest footprint and the two busiest nets' segments (symbols + wire
bundles on sch) — so the style preview covers the real range of shapes.
- PresenceTuner: Colors section rebuilt as explicit modes (per-user / fixed /
palette) with preset palettes (default, pastel, vivid, okabe-ito), buffered
hex editing + Apply (the old always-filtering textarea ate keystrokes), an
'overlay only' hint; demo injection consumes the varied demo set; 'exact
outline (pcb)' in the shape list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-07 10:41:15 +02:00
|
|
|
static std::string collabTestDemoSet()
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestDemoSet() : schCollabTestDemoSet();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 15:59:51 +02:00
|
|
|
static std::string collabGetViewport()
|
|
|
|
|
{
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
return pcbEditorActive() ? pcbCollabGetViewport() : schCollabGetViewport();
|
2026-07-06 15:59:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabGetSelection()
|
|
|
|
|
{
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
return pcbEditorActive() ? pcbCollabGetSelection() : schCollabGetSelection();
|
2026-07-06 15:59:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabTestSelectFirst()
|
|
|
|
|
{
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
return pcbEditorActive() ? pcbCollabTestSelectFirst() : schCollabTestSelectFirst();
|
2026-07-06 15:59:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool collabTestClearSelection()
|
|
|
|
|
{
|
feat(collab): presence P3 — eeschema port (collab-presence 0003)
- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
(SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
warm-up — the bound room's awareness then holds every project peer, so no
multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
no ghost cursor after rebind). eeschema-collab/subschema stay green.
Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:05:15 +02:00
|
|
|
return pcbEditorActive() ? pcbCollabTestClearSelection() : schCollabTestClearSelection();
|
2026-07-06 15:59:51 +02:00
|
|
|
}
|
|
|
|
|
|
2026-07-02 14:48:11 +02:00
|
|
|
|
|
|
|
|
EMSCRIPTEN_BINDINGS(kicad_editor) {
|
|
|
|
|
// Programmatic file open (preferred over UI automation from the web app).
|
|
|
|
|
function("kicadOpenFile", &kicadOpenFile);
|
|
|
|
|
|
|
|
|
|
// Yjs collaborative bridge entry points — same JS contract as the standalone
|
|
|
|
|
// bundles, dispatched on the active editor frame.
|
|
|
|
|
function("kicadCollabApply", &collabApply);
|
|
|
|
|
function("kicadCollabSnapshot", &collabSnapshot);
|
|
|
|
|
function("kicadCollabApplyItems", &collabApplyItems);
|
|
|
|
|
function("kicadCollabSnapshotItems", &collabSnapshotItems);
|
|
|
|
|
function("kicadCollabTestMoveFirst", &collabTestMoveFirst);
|
|
|
|
|
function("kicadCollabGetPos", &collabGetPos);
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
// ysync-review repro hooks (shared names; per-editor-only hooks — pad size,
|
|
|
|
|
// endpoint, field text — flow from the per-editor blocks unchanged).
|
|
|
|
|
function("kicadCollabTestRemoveItem", &collabTestRemoveItem);
|
|
|
|
|
function("kicadCollabTestRotateItem", &collabTestRotateItem);
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
// Presence (collab-presence 0002/0003) + comment pins/panning (0005).
|
2026-07-06 15:59:51 +02:00
|
|
|
function("kicadCollabPresenceStart", &collabPresenceStart);
|
|
|
|
|
function("kicadCollabSetRemote", &collabSetRemote);
|
feat(comments): figma-like comment pins + threads (collab-presence 0005)
Hybrid pins: the wasm draws the dot (kicadCollabSetPins rides the presence
VIEW_OVERLAY, author color + white ring, drawn above selections; zero
kicad-fork changes), the DOM owns interaction —
- comments.ts: controller gluing the MIT kdoc_comments helpers to the editor:
anchor resolution per tool IU (pins track item moves via kdoc_items
observation), throttled pin snapshots, anchorAt nearest-item snap, jumpTo
via new kicadCollabSetViewport; rebinds per sheet like presence.
- CommentLayer.tsx: comment mode (click catcher + composer), pin hit targets
over the GAL dots, thread popover (reply/edit/delete own, resolve/reopen,
delete thread), panel with resolved filter + jump-to (popover centers when
the pin is off-screen). Resolved pins drop figma-style.
- WasmTool: controller lifecycle beside presence; live viewport feed;
window.__pcbjamComments test handle (threads persist in the room ydoc).
- e2e tests/web/comments.spec.ts: two-tab create → reply → resolve → panel
filter → delete, passing vs real partykit; presence suites + collab units
stay green; shared pointer bump (0004 model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 17:50:11 +02:00
|
|
|
function("kicadCollabSetPins", &collabSetPins);
|
|
|
|
|
function("kicadCollabSetViewport", &collabSetViewport);
|
feat(collab): dev-time presence style tuner (VITE_PRESENCE_TUNER=1)
Parametrizes every visual knob of the presence overlay so we can pick the
shipped look live, then wire the winners into the defaults:
- collab_presence_style.h: shared STYLE struct + drawing (now used by BOTH
editor TUs — no more duplicated overlay code): selection shape (rect /
corner brackets / underline / rounded rect / filled-only), border width +
alpha, infill alpha, padding, corner radius; name tag show/size/chip-
background/inside-outside/top-bottom/start-end-center/offset; cursor shape
(cross / pointer / circle+dot), size/width/alpha + label knobs; fixed-color
and palette-by-name-hash overrides (try palettes without changing what
senders publish); pin radius/ring/alphas. Defaults == shipped look.
- kicadCollabSetStyle(json) live-patch export + kicadCollabTestListItems(n)
(real KIIDs for synthetic previews); merged dispatch; pins now carry the
author name so palette overrides recolor them consistently.
- PresenceTuner.tsx: floating dev panel (env-gated, tree-shaken otherwise) —
grouped sliders/selects, demo peers+pins injection for SOLO tuning,
localStorage persistence across reloads, Copy JSON export, reset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-06 19:10:40 +02:00
|
|
|
function("kicadCollabSetStyle", &collabSetStyle);
|
|
|
|
|
function("kicadCollabTestListItems", &collabTestListItems);
|
feat(collab): tuner round 2 — center-anchored labels, exact outlines, varied demo set, clearer color modes
- collab_presence_style.h: GAL BitmapText CENTERS on its position (confirmed
in GAL::ResetTextAttributes — the mispositioned nameplates); labels/chips
now hand GAL the block center. New selection shape 5 'exact outline':
pcbnew hugs real geometry (footprint bounding hull, TransformShapeToPolygon
for the rest, padding inflates the polygon); eeschema falls back to rect.
- kicadCollabTestDemoSet (both TUs + merged): labeled demo groups — smallest
+ largest footprint and the two busiest nets' segments (symbols + wire
bundles on sch) — so the style preview covers the real range of shapes.
- PresenceTuner: Colors section rebuilt as explicit modes (per-user / fixed /
palette) with preset palettes (default, pastel, vivid, okabe-ito), buffered
hex editing + Apply (the old always-filtering textarea ate keystrokes), an
'overlay only' hint; demo injection consumes the varied demo set; 'exact
outline (pcb)' in the shape list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
2026-07-07 10:41:15 +02:00
|
|
|
function("kicadCollabTestDemoSet", &collabTestDemoSet);
|
2026-07-06 15:59:51 +02:00
|
|
|
function("kicadCollabGetViewport", &collabGetViewport);
|
|
|
|
|
function("kicadCollabGetSelection", &collabGetSelection);
|
|
|
|
|
function("kicadCollabTestSelectFirst", &collabTestSelectFirst);
|
|
|
|
|
function("kicadCollabTestClearSelection", &collabTestClearSelection);
|
2026-07-02 14:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // __EMSCRIPTEN__
|