A prefab with no entry script cannot generate any content, so every instance of one stays permanently empty.
Scripts are meant to be for procedural/dynamic prefabs only — a prefab whose master is just hand-authored geometry should stamp that geometry into its instances. That half was never built. MapDataProvider.regeneratePrefabInstance (lib/provider/map_data_state.dart) bails out when prefab.scriptId == null, and the no-script/token path is designed in docs/prefab_tokens.md, which is explicit that it is "design only, nothing implemented yet".
Why this is user-facing, not just an internal gap
The Explorer's promote-to-prefab action calls addPrefab(masterCollectionId: collectionId) with no scriptId (lib/pages/professional/widgets/explorer_panel.dart:473). Nothing anywhere in lib/pages/** sets prefab.scriptId — there is no UI to attach a script to a prefab at all.
So every prefab created through the UI is permanently dead: promote artwork, place an instance, get nothing. The only working path today is via the agent tools (create a script object, then set scriptId on the prefab).
Partially mitigated already
Failed generation now records an errorMessage on the instance and prints to console instead of silently no-oping, so the failure is at least diagnosable — read_hierarchy and the script editor panel surface it. Covered by test/prefab_generation_errors_test.dart. The underlying feature is still missing.
Remaining work
Implement the token path per docs/prefab_tokens.md: fixed stamp, clone every descendant with fresh ids and remapped internal references (node ids, segment endpoints, parent/child links), {{token}} find-and-replace for surfaced instance properties.
The doc's open questions are still open. The significant one: cloned stations/segments keep the master's exact MetroLine ids, so every instance would attach to the same line(s) as the master with no per-instance remap — fine for decorative shapes, a real gap for anything meant to be reused across lines.
Related bug found alongside
setPrefabScript does not regenerate a prefab's live instances (regenerateAllInstancesOfPrefab exists but isn't called), so even on the working scripted path, attaching a script to an existing prefab leaves its instances stale until they are recreated.
A prefab with no entry script cannot generate any content, so every instance of one stays permanently empty.
Scripts are meant to be for procedural/dynamic prefabs only — a prefab whose master is just hand-authored geometry should stamp that geometry into its instances. That half was never built. `MapDataProvider.regeneratePrefabInstance` (`lib/provider/map_data_state.dart`) bails out when `prefab.scriptId == null`, and the no-script/token path is designed in `docs/prefab_tokens.md`, which is explicit that it is "design only, nothing implemented yet".
**Why this is user-facing, not just an internal gap**
The Explorer's promote-to-prefab action calls `addPrefab(masterCollectionId: collectionId)` with no scriptId (`lib/pages/professional/widgets/explorer_panel.dart:473`). Nothing anywhere in `lib/pages/**` sets `prefab.scriptId` — there is no UI to attach a script to a prefab at all.
So every prefab created through the UI is permanently dead: promote artwork, place an instance, get nothing. The only working path today is via the agent tools (create a `script` object, then set `scriptId` on the prefab).
**Partially mitigated already**
Failed generation now records an `errorMessage` on the instance and prints to console instead of silently no-oping, so the failure is at least diagnosable — `read_hierarchy` and the script editor panel surface it. Covered by `test/prefab_generation_errors_test.dart`. The underlying feature is still missing.
**Remaining work**
Implement the token path per `docs/prefab_tokens.md`: fixed stamp, clone every descendant with fresh ids and remapped internal references (node ids, segment endpoints, parent/child links), `{{token}}` find-and-replace for surfaced instance properties.
The doc's open questions are still open. The significant one: cloned stations/segments keep the master's exact `MetroLine` ids, so every instance would attach to the same line(s) as the master with no per-instance remap — fine for decorative shapes, a real gap for anything meant to be reused across lines.
**Related bug found alongside**
`setPrefabScript` does not regenerate a prefab's live instances (`regenerateAllInstancesOfPrefab` exists but isn't called), so even on the working scripted path, attaching a script to an existing prefab leaves its instances stale until they are recreated.
Stamping is implemented for canvas objects, so the headline case here is fixed: promote a collection, place an instance, and the master's contents are cloned into it. {{token}} substitution works and surfaces one editable string property per distinct token name.
What landed: lib/scripting/prefab_stamping.dart (stampPrefabInstance, plus tokenNamesIn and substituteTokens as separately testable pieces); a canvasObjectsUnderCollection helper on MapDataProvider that sweeps nested collections to a fixpoint while preserving document order, so a stamp keeps the master's z-order; and the no-script branch of regeneratePrefabInstance now stamping instead of erroring. An empty master is still an error rather than a silently blank instance — letting it stamp nothing would recreate the invisible-failure problem this issue was opened about.
The related bug noted above is fixed too: setPrefabScript now calls regenerateAllInstancesOfPrefab, so attaching a script no longer leaves live instances stale.
Still outstanding, and why this stays open: stations, segments, nodes and nested collections are not cloned. Instance ownership (generatedChildIds feeding updatePrefabInstanceGeneration) is typed to canvas objects only, and extending it means teaching serialisation, deletion guards, hide-cascade and selection-locking about instance-owned track, plus answering the design doc's line-reference question. Nested collections currently flatten into the instance, so stamp then re-promote won't reproduce the original hierarchy.
Tests: test/prefab_stamping_test.dart (17 cases) plus updates to test/prefab_generation_errors_test.dart; 138 passing across the prefab suite.
Stamping is implemented for canvas objects, so the headline case here is fixed: promote a collection, place an instance, and the master's contents are cloned into it. `{{token}}` substitution works and surfaces one editable string property per distinct token name.
What landed: `lib/scripting/prefab_stamping.dart` (`stampPrefabInstance`, plus `tokenNamesIn` and `substituteTokens` as separately testable pieces); a `canvasObjectsUnderCollection` helper on `MapDataProvider` that sweeps nested collections to a fixpoint while preserving document order, so a stamp keeps the master's z-order; and the no-script branch of `regeneratePrefabInstance` now stamping instead of erroring. An empty master is still an error rather than a silently blank instance — letting it stamp nothing would recreate the invisible-failure problem this issue was opened about.
The related bug noted above is fixed too: `setPrefabScript` now calls `regenerateAllInstancesOfPrefab`, so attaching a script no longer leaves live instances stale.
Still outstanding, and why this stays open: stations, segments, nodes and nested collections are not cloned. Instance ownership (`generatedChildIds` feeding `updatePrefabInstanceGeneration`) is typed to canvas objects only, and extending it means teaching serialisation, deletion guards, hide-cascade and selection-locking about instance-owned track, plus answering the design doc's line-reference question. Nested collections currently flatten into the instance, so stamp then re-promote won't reproduce the original hierarchy.
Tests: `test/prefab_stamping_test.dart` (17 cases) plus updates to `test/prefab_generation_errors_test.dart`; 138 passing across the prefab suite.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
A prefab with no entry script cannot generate any content, so every instance of one stays permanently empty.
Scripts are meant to be for procedural/dynamic prefabs only — a prefab whose master is just hand-authored geometry should stamp that geometry into its instances. That half was never built.
MapDataProvider.regeneratePrefabInstance(lib/provider/map_data_state.dart) bails out whenprefab.scriptId == null, and the no-script/token path is designed indocs/prefab_tokens.md, which is explicit that it is "design only, nothing implemented yet".Why this is user-facing, not just an internal gap
The Explorer's promote-to-prefab action calls
addPrefab(masterCollectionId: collectionId)with no scriptId (lib/pages/professional/widgets/explorer_panel.dart:473). Nothing anywhere inlib/pages/**setsprefab.scriptId— there is no UI to attach a script to a prefab at all.So every prefab created through the UI is permanently dead: promote artwork, place an instance, get nothing. The only working path today is via the agent tools (create a
scriptobject, then setscriptIdon the prefab).Partially mitigated already
Failed generation now records an
errorMessageon the instance and prints to console instead of silently no-oping, so the failure is at least diagnosable —read_hierarchyand the script editor panel surface it. Covered bytest/prefab_generation_errors_test.dart. The underlying feature is still missing.Remaining work
Implement the token path per
docs/prefab_tokens.md: fixed stamp, clone every descendant with fresh ids and remapped internal references (node ids, segment endpoints, parent/child links),{{token}}find-and-replace for surfaced instance properties.The doc's open questions are still open. The significant one: cloned stations/segments keep the master's exact
MetroLineids, so every instance would attach to the same line(s) as the master with no per-instance remap — fine for decorative shapes, a real gap for anything meant to be reused across lines.Related bug found alongside
setPrefabScriptdoes not regenerate a prefab's live instances (regenerateAllInstancesOfPrefabexists but isn't called), so even on the working scripted path, attaching a script to an existing prefab leaves its instances stale until they are recreated.Stamping is implemented for canvas objects, so the headline case here is fixed: promote a collection, place an instance, and the master's contents are cloned into it.
{{token}}substitution works and surfaces one editable string property per distinct token name.What landed:
lib/scripting/prefab_stamping.dart(stampPrefabInstance, plustokenNamesInandsubstituteTokensas separately testable pieces); acanvasObjectsUnderCollectionhelper onMapDataProviderthat sweeps nested collections to a fixpoint while preserving document order, so a stamp keeps the master's z-order; and the no-script branch ofregeneratePrefabInstancenow stamping instead of erroring. An empty master is still an error rather than a silently blank instance — letting it stamp nothing would recreate the invisible-failure problem this issue was opened about.The related bug noted above is fixed too:
setPrefabScriptnow callsregenerateAllInstancesOfPrefab, so attaching a script no longer leaves live instances stale.Still outstanding, and why this stays open: stations, segments, nodes and nested collections are not cloned. Instance ownership (
generatedChildIdsfeedingupdatePrefabInstanceGeneration) is typed to canvas objects only, and extending it means teaching serialisation, deletion guards, hide-cascade and selection-locking about instance-owned track, plus answering the design doc's line-reference question. Nested collections currently flatten into the instance, so stamp then re-promote won't reproduce the original hierarchy.Tests:
test/prefab_stamping_test.dart(17 cases) plus updates totest/prefab_generation_errors_test.dart; 138 passing across the prefab suite.