Static (no-script) prefabs generate nothing — UI can only create dead prefabs #35

Open
opened 2026-08-19 04:29:12 +00:00 by ImBenji · 1 comment
Owner

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.
ImBenji added the bugenhancement labels 2026-08-19 04:29:12 +00:00
ImBenji added this to the Arcs & Angles project 2026-08-19 04:29:12 +00:00
Author
Owner

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.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: IMBENJI.NET/Metro-Map-Maker#35