Files
solvecraft/docs/book/src/dev/local-libraries.md
T
selune 9e6e0b8df1 Render workspace: complete experimental ribbon, resources and effects integration (#5493) (#5494)
* wip(render): reconcile completed material and image pipeline source with 0.20 (#5493)

Source-only integration reference for staged review, not a merge-ready aggregate.
Donor: 0xlillith/solidcraft@aea20b0115.
Upstream: 858e5995d6.

Retain original CPU/material contracts and explicit GPU donor provenance in
docs/render-materials-lab.md (#2067, #2191, #2780, #3306). Preserve released
format migrations and current navigation/startup/shell behavior. New saved
records use pending descriptors. The physical-card descriptor follows the
maintainer's material-engineering-cards naming request, with a legacy-lab
format-29 regression. Replace raw new panel hosts with shared containers.

Repository checks, complete workspace/all-target Clippy, and the independent
physical/resource authoring checks pass for this source. The fresh full local
CI invocation has reached test compilation and is not yet complete. Do not
transfer donor native output or prior test totals to this integration.

Generated review screenshots, video, package ZIP and machine logs remain at
the immutable personal evidence pin. Uncommitted geometric displacement is
backed up separately, not silently included. No kernel/vendor change, direct
main write, release or independent contributor-branch rewrite.

Co-authored-by: Christian Svensson <blue@cmd.nu>

* test(cli): pin the Compact camera-sample admission diagnostic (#5493)

The bounded request still refuses 1024x1024x64 samples before host initialization and writes no output. Update only the stale expected diagnostic to the existing Compact budget wording; production limits and code are unchanged. Exact-tree CLI regression suite: 14 passed, 0 failed. The full repository gate has been invoked separately and is not yet complete.

* Normalize UI container violation paths across platforms

Report repository-relative paths with forward slashes so diagnostics and the existing nested-package regression assertions agree on Windows and Unix. Keep the container detection rules unchanged.

Validation: official ui-containers gate and all seven focused xtask tests passed; rustfmt and diff checks passed. Only xtask/dependencies were compiled; no application build or heavy tests.
(cherry picked from commit 44b58d8e10)

* fix(render): preserve camera contracts and correct acceptance regressions (#5493)

Preserve Design view.apply semantics with a separate strict Render camera command. Retain existing translations when English-only aliases collide; add material-axis entries and camera-specific pitch labels. Compare complete validated engineering cards and retain job handles before cancellation.

Focused and native acceptance is pinned to tree f8a423b21f. Full CI has been invoked separately and is not claimed green. Landing follows the render integration policy in #5493.

* fix(render): resolve showcase licence and upstream resource hygiene (#5493)

Record SychPL's explicit MIT OR Apache-2.0 grant, retaining source/model bytes and the Ubuntu lettering notice. Remove 80 absent attribution rows, personal fork records, dead delivery attributes and three fork/resource-only workflows. Existing xtask assets now performs bounded offline hash checks and rejects orphan render attribution; no parallel draft CI or package installation. Original authoring reproduction remains explicit. Scoped xtask tests, assets, Clippy, formatting and prepared SELENE validation pass; no application or renderer-wide result is inferred.

* fix(render): align saved bounds and progressive sample resolution (#5493)

Address review r4364211669/r4364211677/r4364211681/r4364211691/r4364211695. Persisted light/frame domains respect the existing 1e9 document bound; related LED/rectangle/direction cases use the same bound. Workstation primary resolve shares the 4096 admission cap and film counters use checked conversions. Exact candidate: 485 CPU render tests, 21 render document tests and strict scoped Clippy pass, including positive boundary round trips and 2048/4096 end-to-end checkpoints. No released format/migration edits, relaxed test limits or full-stack acceptance claim.

* wip(render): isolate optional resources and harden sample handling (#5493)

Review work in progress: opt-in encoded render library with reproducible runtime catalog exports; native-only robust dependency through the workspace; checked bloom slices; per-sample point-light diagnostics; independent area-light spatial/film keys. Resource-module binaries in both configurations, generation, Cargo production feature graphs and attribution checks pass. Full engine/render regression and combined acceptance are pending: do not merge this donor as a constituent or treat scoped resource proof as runtime acceptance.

* fix(gpu): preserve donor allocations through the scope-safety repair (#5722)

Port the native-validated #5723 scope-cleanup correction into the experimental donor, retaining its adaptive, volume, aging, photographic and bloom allocations. Same reverse-drain helper and regression cases; the donor combination still needs its own compile/test gate and is not covered retroactively by render-base results.

* claim: #1369

* Reject unknown pending concepts after format folding (#1369)

* test(render): close bounded sampling and bloom review regressions (#5493)

Validate the optional-resource/lighting/dependency donor at its exact tree. Required Vulkan GPU 127/0/3; CPU renderer 487/0; engine Render 72/0; document render 21/0; lean library 7/0; strict scoped Clippy, assets/layers/lists/containers and lean-engine WASM pass. Preserve original failed controller/typing attempts. This is the draft donor/disposition source, not a replacement for constituent render PRs or final main acceptance.

* wip(render): preserve stable aging target validation candidate

Exact staged source from prior review work on donor 3b892eab5e. This is a recovery/review checkpoint, NOT accepted delivery. An actual command-path regression currently fails because the selected executor refuses ordered surface aging. No assertion, capability or admission limit is weakened. Native/UI/full combination acceptance remains pending. Saved/runtime split adds one pending descriptor and retains original file scope; no main/render branch is changed.

* test(render): preserve numeric setup intent at the admitted coordinate bound

Follow up jyviko review on #5494 without weakening the corrected saved-coordinate contract. The positive clicked fixture uses 1e9 instead of inadmissible 2e9; explicit out-of-range cases still refuse, and the full saved setup round-trips through JSON and the native container. Exact-source Render workspace 95/0 and strict all-target UI Clippy pass. This does not incorporate the separately failing stable-aging candidate or claim full current-render acceptance.

* test(render): use the real GPU executor for saved aging

Move successful native cold-reopen Check/Start coverage from the CPU-backed protocol fixture into the production GPU executor tests. Verify capture-index changes preserve the stable target and that enabling aging changes both PNG and raw EXR output. Retain explicit, allocation-free refusal coverage for executors without aging support. Production capabilities and admission checks are unchanged.

* fix(render): persist stable identities for targeted aging (#5493)

Separate saved RenderBodyTarget identities from captured mesh ordinals. Reject legacy ambiguous targets, resolve Check/Start after visibility changes and preserve native reopening, copies and undo. Unsupported executors still refuse; real AMD Vulkan regression completes saved aging after reordered capture.

Source tree 6b84c8ad passes document 23, engine Render 75, GPU effects 5 and Render UI 95 with no failures; scoped strict Clippy, WASM and repository gates pass. Fresh CLI/native reopen and clean/aged GPU exports pass with identical physical totals and inspected actual images. Whole current-render integration is separate.

* fix(render): reconcile combined CPU/GPU contracts on current upstream

Unify captured resources/status and CPU-vs-GPU request schemas after the real two-parent integration; remove obsolete duplicate Vulkan selector and retain combined platform-filter regression. Deduplicate only identical or superseded test definitions, retaining the stronger card metadata and reserved-executor assertions. No assertions, admission limits or feature refusals are weakened.

All targets of render dependencies, GPU, engine, UI, CLI and native app pass cargo check with raytrace-cpu and bundled-render-library at tree c70d00d1. Native executable tests and full current-source acceptance remain pending. This is a private integration rehearsal for subsequent constituent PRs, not an aggregate official render/main merge.

* test(render): retain one complete host lifetime regression set

Deduplicate byte-identical DropProbe/task-lifetime tests and retain the adapted environment/texture ownership regressions with every assertion and complete memory estimate. Keep the registered-geometry admission regression once; only struct field order differed. Replace a one-element diagnostic loop with its equivalent block, preserving all wrap/width assertions.

Test-only integration repair. Formatting and diff checks pass; refreshed executable validation is required. No production behavior, limits, assertions or ignores changed.

* fix(doc): recognize the proven format-29 card descriptor alias

Normalize only the historical format-29 physical-material-cards spelling, and only when material-engineering-cards is registered. Admission and migration de-duplication use the same identity. Unknown concepts, wrong versions and incapable readers still refuse before mutation. Six controlled-history Rust regressions and actual CLI migration/no-clobber acceptance pass. No version, released migration or CI changes. Refs #5793, #1369, #5493.

* test(render): preserve grounding refusal before explicit instance moves

Update the two Render binding fixtures for upstream first-occurrence grounding. Verify grounded movement refuses without changing document/history, then explicitly unground through the public command before the intended move. Retain every target, resource, copy and persistence assertion. Refs #5493.

---------

Co-authored-by: Christian Svensson <blue@cmd.nu>
Co-authored-by: Victor Santos Oliveira <56417388+Vittuu@users.noreply.github.com>
Co-authored-by: cfaulkingham <colin.faulkingham@gmail.com>
2026-10-24 14:21:59 +00:00

12 KiB
Raw Blame History

Local material libraries

The local library transports design-owned appearances and physical-material definitions. Portable catalog v2 preserves opaque PBR parameters and validated engineering cards, including SI values, material-local axes, source records and per-property conditions. It reuses the existing commands, file pickers and library contract. The catalog has its own version; no additional design-format change is needed.

Desktop workflow

  1. Apply a named colour/opacity look using Appearance, or define a physical material using Physical Material → New / Edit or the material commands. An appearance does not change physical density.
  2. In Appearance → Local library, choose Export design library.... The snapshot contains explicit body/face/component appearance overrides and design-local physical materials, including their default looks. It does not export imported kernel paint, unassigned built-in catalog entries or an unapplied colour-picker draft.
  3. Open that library in another design, search its appearance presets, select one and choose Apply library appearance. The normal body/face/component targets are reused. OK after this immediate application does not add a second undo step.
  4. To import a physical definition in the same Local library section, enable Physical material definitions, select an entry and review its density/card. Name on import makes a collision explicit: choose another name instead of overwriting existing data. Import material into design copies the definition only. Cancel or OK after copying keeps the import and does not assign either a material or an appearance to any body. Assign the copied material later in Physical Material. Each import is one undo step.
  5. Save the design. Its selected definitions are ordinary copied design data; the source library can be moved or removed without changing the saved result.

Export does not edit the design, its dirty state or history. An existing file is refused unless Replace existing library file is explicitly selected. Export is a snapshot of the design definitions, not an automatic merge with entries in an existing catalog. Editing a copied look/material uses the normal commands and does not edit its source.

Copied look labels are inert data even when equal to a starter.* recipe ID. Reopening Appearance or applying the copied look to another target preserves its color, opacity and PBR response. Library body and face targets use the same world selections as ordinary assignment, including displaced component instances; the outer command maps them into the source component exactly once.

The combined render integration uses main's merged #1127 asynchronous picker. Model edits and tab changes wait for its answer while drawing/resizing continues. Overwrite consent is captured before opening; export snapshots the design when library.export runs after choosing the destination. Document identity is checked, and an old library answer cannot replace another Appearance editor. Cancellation does not read or write a library. The earlier #1114 candidate is no longer a runtime dependency of the refreshed consumer.

The desktop panel applies appearances and imports physical definitions. library.apply also supports explicit body assignment in the same atomic command; imported definitions appear in the existing Physical Material list and can be edited there. The browser can export a library through the existing download service. Interactive local library opening is a desktop feature in this first slice. Browser engine commands can consume a bounded catalog already supplied through VFS; wasm compilation does not prove an interactive browser importer or download workflow.

Commands

All programmatic calls use JSON and never open a file picker:

{"command":"library.export","params":{"path":"my-library.solidcraft-library.json"}}
{"command":"library.inspect","params":{"path":"my-library.solidcraft-library.json"}}

Inspection/export returns a catalog with qualified entry IDs and exact revisions. Use the returned values when applying; do not replace an unknown revision with a guessed one:

{"command":"library.apply","params":{
  "path":"my-library.solidcraft-library.json",
  "entry":"user.local/appearance-<returned-id>",
  "revision":"<returned-64-character-revision>",
  "targets":{"bodies":["Body1"]}
}}

Appearance targets can be bodies, components or faces: [{body, point: [x,y,z]}]. Points are world-space millimetres. At most 1,024 total targets are accepted. Missing objects and invalid targets fail; the importer does not invent a nearby replacement.

A material entry can be copied without targets or assigned to body targets. The optional name explicitly selects a new physical-material name on import. An identical existing definition is reused; a conflicting definition or built-in name is refused. No density, look or configuration cell is silently overwritten. Creation and assignment share one outer undo transaction through the existing material commands. Mass remains the existing volume × density calculation; a generic illustrative density is not an engineering grade.

library.export also accepts id (default user.local), name (default My library), provenance, overwrite (default false) and format (default solidcraft-library/2). Explicit solidcraft-library/1 refuses PBR or engineering-card loss before publishing, including with overwrite enabled. Only explicit assignments/design-local definitions are inspected, without evaluating geometry. Duplicate exact definitions are deduplicated; different values with the same display name remain distinct entries.

Portable catalog v2

solidcraft-library/2 extends the same envelope and definition kinds with optional pbr: {metallic, roughness, dielectric_ior} on appearance values and optional physical_card on material values. PBR uses the bounded opaque contract and requires opacity exactly one. Cards use the existing SI admission and validation rules. Sources and conditions are copied as supplied data, not certification. Card density never replaces assigned mass density. An independent default PBR look and a physical card may coexist in a material.

Applying an appearance is an exact replacement: v1 scalar values and v2 values without PBR clear the target's prior PBR. V2 values with PBR retain their parameters. Display labels are inert, including labels equal to built-in preset IDs: importing an owned value never selects a different recipe. Undo/redo and native save/reopen preserve the copy after removing the source file.

Absent richer fields are omitted from serialization. Existing v1 scalar bytes, content revisions and identities remain exact; pinned appearance bytes and a material revision cover the writer contract. Changing only the envelope version leaves entry revisions unchanged. PBR and complete card data participate in revisions when present. V1 wire input rejects even null v2-only fields. Older readers refuse v2.

Scalar catalog v1 compatibility

The independent JSON format marker is solidcraft-library/1. It has id, name and an entries array. Each entry has id, revision, provenance and a typed definition:

  • appearance: value: {name, color: [r,g,b], opacity}; sRGB bytes and finite opacity 0–1.
  • material: value: {name, density_g_cm3, appearance?}; finite density above 0 and at most 1,000 g/cm³, with an optional appearance value of the same scalar shape.

Every object rejects unknown fields. Unsupported kinds (including texture/environment payloads) and versions fail explicitly, rather than dropping fields or pretending that a colour preview is a textured material. Catalog IDs are 1–64 ASCII bytes, beginning with a lowercase letter and continuing with lowercase letters, digits, ., _ or -. An entry ID is <catalog-id>/<local-id> with the same local-ID rules; paths and labels are not IDs.

An entry revision is lowercase SHA-256 of compact v1 serde JSON [provenance, definition]. Derived struct field order, omission of absent optional fields, UTF-8 escaping and f64 round-trip number formatting are part of this writer contract; this is not arbitrary JSON canonicalization. Prefer library.export or the Rust Entry::new/content_revision API when authoring revisions. A future incompatible writer changes the catalog version. The default export IDs contain a kind and 16 hex revision characters; collisions are rejected, never used to overwrite a different definition. Explicitly authored stable local IDs can retain their identity across revisions. Application requires the selected exact revision. Changing another entry does not change the selected definition's identity.

Provenance contains a required license, optional author and optional source_url. It is supplied metadata, not verified permission or a publisher signature. URLs are never fetched. The default LicenseRef-User-Provided does not claim that user data is openly licensed. No external art/data is bundled in this slice. Catalog provenance/revisions stay in the catalog: values are copied into existing Look/UserMaterial records without a persistent catalog-origin/update receipt. Card source records and property conditions belong to the card and are copied exactly. Resource embedding and explicit update links remain separate work.

Bounds and failure behavior

The reader accepts at most 4 MiB encoded JSON and 1,024 entries. A bounded raw preflight preserves strict v1 wire fields before typed decoding. Entry decoding stops at the count cap with fallible vector growth. Names are trimmed, nonempty and at most 128 UTF-8 bytes; provenance license/author/source URL limits are 128/256/2,048 bytes. Control characters, invalid identifiers, duplicate identities, bad revisions and nonfinite scalar values fail. Export inspects at most 100,000 source references, deduplicating into at most 1,024 entries. Export bounds retained unique definitions before whole-catalog encoding, reserving 4 KiB for the envelope and counting each entry's pretty bytes plus nested indentation. This conservative admission may refuse a near-limit compact catalog. Physical imports also obey the design's 1,000-material cap. These are encoded/work limits, not a process-memory or latency guarantee.

Native reads are bounded regular-file reads; browser reads check VFS size before cloning. Native no-clobber writes reuse atomic new-file publication; explicit replacement is atomic without reading/backing up an arbitrarily large old target. All library command paths obey the active MCP/control file scope before reading or publishing, including overwrite. Browser VFS publication is synchronous and reuses the host's download service. No automatic discovery, asset fetch, relative-resource resolution, executable recipe or plugin is introduced.

Failed application preserves the document and undo/redo history. The source file is read and checked before copying; a stale selected revision needs an explicit reload/reselection. The copied design remains independent after successful assignment, undo/redo and cold reopening. This library has no dependency on the pending render stack and does not change the document format. User-visible evidence and actual native/wasm results are recorded in the PR; geometry/robustness checks remain separate and no reference baseline is weakened.

Scope

The catalog carries the document's scalar/opaque Look and engineering-card values. It does not transport GPU2 runtime overrides, refractive glass, clearcoat, texture resources, mappings, image files or environment maps. The six starter glass recipes remain recipes; v2 does not turn an IOR or alpha preview into refraction. Unknown resource kinds and fields fail explicitly. A runtime GPU-only look must not be presented as captured by this design-definition export.