1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! Imported appearance — the display colour an exchange format carries, in the
//! kernel's own terms.
//!
//! **Where colour LIVES.** The kernel has no colour field on `BrepSolid`, and it
//! does not need one: colour is scene metadata, keyed by the face/solid NAME in
//! `feature_pipeline::scene_metadata`. This module is only the CARRIER between
//! "the importer read a colour" and "the pipeline stamped it on a name" — it is
//! deliberately not a storage layer, and nothing here is serialized.
//!
//! **The record shape (THE convention, one spelling everywhere).** A colour is
//! stamped as a single string attribute on the entity's own metadata record:
//!
//! ```text
//! { "color": "#RRGGBB" }
//! ```
//!
//! * key [`COLOR_METADATA_KEY`] — `color`, US spelling, matching
//! `BREP_render/src/color.rs` and the caller-side colour params.
//! * value — uppercase `#RRGGBB` sRGB hex, the form the info/metadata panel shows
//! and a human can type back. [`ImportedColor::to_hex`] is the ONE producer.
//!
//! The record rides on the FINAL, stamped name, so it is captured by
//! `io/snapshot.rs` into the native IMPORT3D payload and restored with the
//! geometry — an imported colour survives save/reload and the parts library for
//! free (`docs/developer/kernel-plans/step-assembly-import.md` §3.8).
//!
//! **Precedence.** A face colour is stamped on the FACE name; a body colour on
//! the BODY name only. A body colour is never fanned out onto its faces: the
//! solid's own info window already surfaces it, and materializing it per face
//! would make the face records claim a styling the file never authored.
//!
//! **Units.** Exchange formats give components as 0..1 doubles with no gamma
//! statement; OCC, FreeCAD and every viewer that reads them treat the value as
//! sRGB and scale it straight to 8 bits, so `round(c * 255)` is the conversion —
//! no linear/sRGB transfer applied.
/// The scene-metadata key an imported colour is stamped under. ONE spelling.
pub const COLOR_METADATA_KEY: &str = "color";
/// An imported display colour: sRGB components in 0..=1, kept as read.
///
/// The float form is preserved (rather than collapsing to 8-bit at read time) so
/// a later viewport lane can use the exact authored value; the metadata record
/// carries the [`Self::to_hex`] rendering of it.
/// One imported body's appearance: an optional body-wide colour plus an optional
/// colour per FACE.
///
/// `faces` is POSITIONAL and parallel to the body's faces in shell/face order —
/// the same walk `feature_pipeline::features::import3d::stamp_imported_names`
/// uses — so index `i` is the i-th face of `solid.shells.iter().flat_map(faces)`.
/// It is either empty (nothing read) or exactly as long as that face count; a
/// producer that cannot guarantee the pairing must leave it EMPTY rather than
/// emit a shorter or speculative list.
// BREP private tests: a1fa8d400a8e2883