@toolpath/dfm 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,113 +1,57 @@
1
1
  # Toolpath DFM
2
2
 
3
- `@toolpath/dfm` is the DFM (design for manufacturing) rule list: each rule
4
- written as the sentence it is — "Holes with L/D to top of part ≥ 8" — whose
5
- words are its fields, beside its colour and how many of a part's features
6
- break it. Under the list, Import, Export and Copy LLM prompt share a rule set
7
- as one JSON file.
3
+ `@toolpath/dfm` is the DFM (design for manufacturing) rules and the part
4
+ checker: what a rule is, how a part's features break it, and the rule-set file
5
+ a set is shared in. **It is logic, data types and functions only** — no React,
6
+ no DOM, no CSS — so a server route can import it as readily as a browser.
8
7
 
9
- It also draws a feature's reach chart: the walls beside the feature, how high
10
- they stand and how far out.
11
-
12
- And it shows a feature as the Engine read it — the feature panel: the features
13
- a clicked face could mean, the rules the chosen one breaks, what was measured
14
- of it, its reach, and its datasheet as sent. Its pinch points, the widest tool
15
- standing where the feature is tightest, are placed here and drawn by
16
- `@toolpath/viewer`.
17
-
18
- The rules and the checker that counts them ship too, with no React, under
19
- `@toolpath/dfm/model`.
8
+ The views that show and edit the rules — `RuleList`, `ReachChart`,
9
+ `FeaturePanel` — are in [`@toolpath/ui`](https://www.npmjs.com/package/@toolpath/ui).
20
10
 
21
11
  ## Install
22
12
 
23
13
  ```sh
24
- npm install @toolpath/dfm @toolpath/ui react react-dom
25
- ```
26
-
27
- Add the styles after Tailwind and the `@toolpath/ui` theme:
28
-
29
- ```css
30
- @import 'tailwindcss';
31
- @import '@toolpath/ui/theme.css';
32
- @import '@toolpath/dfm/dfm.css';
14
+ npm install @toolpath/dfm
33
15
  ```
34
16
 
35
17
  ## Exports
36
18
 
37
- | Entry point | What it is |
38
- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
39
- | `@toolpath/dfm` | `RuleList`, `Swatch`, the list's keyboard helpers, `ReachChart`, `ReachDrawing`, the feature panel (`FeaturePanel`, `FeatureDetails`, `CandidateList`, `ComparisonTable`, `storageFolds`), their types, and the two rule vocabularies (`MILLING_RULES`, `TURNING_RULES`) |
40
- | `@toolpath/dfm/model` | The rules, `checkPart` and `checkTurnedPart`, the rule-set file, the feature panel's rows, pinch points — no React, no DOM |
41
- | `@toolpath/dfm/dfm.css` | Lets the app's Tailwind see the list's and chart's classes |
19
+ | Entry point | What it is |
20
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
21
+ | `@toolpath/dfm` | The rules and both vocabularies (`MILLING_RULES`, `TURNING_RULES`), `checkPart` and `checkTurnedPart`, the rule-set file and `llmRulePrompt`, the feature panel's rows, pinch points |
22
+ | `@toolpath/dfm/model` | The same entry, under its name from before the views moved |
42
23
 
43
24
  ## The rules are an input
44
25
 
45
- The package ships no default rules and stores nothing — not the rules, nor
46
- which of the feature panel's sections are open. The app keeps the rules
47
- — in memory, `localStorage`, a server — and passes them in with the functions
48
- that change them:
49
-
50
- ```tsx
51
- import { RuleList, type DfmRules } from '@toolpath/dfm'
52
- import { checkPart, dfmFeatures } from '@toolpath/dfm/model'
26
+ The package ships no default rules and stores nothing. The app keeps the rules
27
+ — in memory, `localStorage`, a server — and checks a part against them:
53
28
 
54
- const rules: DfmRules = { rules, add, update, remove, replace }
29
+ ```ts
30
+ import { checkPart, dfmFeatures } from '@toolpath/dfm'
55
31
 
56
32
  // From a part analysis: the Engine's report, and each feature's datasheet.
57
33
  const features = dfmFeatures(report.features)
58
- const check = checkPart(features, { sheets, datasheets, regionAreas }, rules.rules)
59
-
60
- <RuleList
61
- rules={rules}
62
- check={check} // null while the part is still being analysed
63
- features={features}
64
- sheets={sheets}
65
- units="mm"
66
- selected={selectedTag}
67
- selectedGroup={selectedGroup}
68
- onInspect={(tag, group) => inspect(tag, group)}
69
- onHover={(hovered) => highlight(hovered)}
70
- />
34
+ const check = checkPart(features, { sheets, datasheets, regionAreas }, rules)
71
35
  ```
72
36
 
73
37
  `sheets` is each feature's measurements, built with `featureSheet` from its
74
38
  datasheet; `datasheets` is the datasheets as the API sent them, both by
75
39
  lower-cased feature tag; `regionAreas` is each face's area by region index.
76
40
 
77
- Put `ruleListKeys` on the panel that holds the list, so the arrow keys walk the
78
- rules from anywhere in it.
79
-
80
- `actions` puts the app's own buttons at the end of the footer's row, after
81
- Import…, Export and Copy LLM prompt — a way back to the app's default rules,
82
- say, since the package has none of its own.
83
-
84
41
  ## Turning rules
85
42
 
86
- The same list edits turning rules: pass `vocabulary={TURNING_RULES}`, and it
87
- offers turned subjects (grooves, threads, axial holes, OD and ID features) and
88
- their measures, saves its set as `dfm-turning-rules.json`, and writes its LLM
89
- prompt for a lathe. Each vocabulary keeps its own rules: an import refuses the
90
- other process's file, and `parseRules(raw, TURNING_RULES)` drops milling ones.
91
- Every helper that reads a rule takes the vocabulary last, and reads milling
92
- where it is left out.
43
+ `TURNING_RULES` is the turning vocabulary: turned subjects (grooves, threads,
44
+ axial holes, OD and ID features) and their measures. Each vocabulary keeps its
45
+ own rules: a rule-set file of the other process is refused, and
46
+ `parseRules(raw, TURNING_RULES)` drops milling ones. Every helper that reads a
47
+ rule takes the vocabulary last, and reads milling where it is left out.
93
48
 
94
- ```tsx
95
- import { RuleList, TURNING_RULES } from '@toolpath/dfm'
96
- import { checkTurnedPart, turnedStretches } from '@toolpath/dfm/model'
49
+ ```ts
50
+ import { checkTurnedPart, turnedStretches } from '@toolpath/dfm'
97
51
 
98
52
  // From a part analysis's `turning.features`.
99
53
  const stretches = turnedStretches(report.turning.features)
100
- const check = checkTurnedPart(stretches, rules.rules)
101
-
102
- <RuleList
103
- rules={rules}
104
- vocabulary={TURNING_RULES}
105
- check={check}
106
- features={stretches}
107
- sheets={{}}
108
- units="mm"
109
- {...rest}
110
- />
54
+ const check = checkTurnedPart(stretches, rules)
111
55
  ```
112
56
 
113
57
  The Engine reports a stretch both ends of the part reach as two features, one
@@ -117,120 +61,23 @@ every stretch counts — a turned face has one reading — so nothing is left in
117
61
  `otherTags`. Turning is experimental in the API, so a datasheet field that is
118
62
  missing or malformed is no figure, never an error.
119
63
 
120
- ## Reach chart
121
-
122
- `ReachChart` draws a feature's reach curve: the section through the part at the
123
- feature's wall, to scale. The feature is on the left, in blue; the walls step up
124
- on the right, with their heights and their distances from the feature written
125
- on. Pointing at the walls reads the curve at that distance.
126
-
127
- ```tsx
128
- import { ReachChart, ReachDrawing } from '@toolpath/dfm'
129
- import { featureProfile, readReachCurve } from '@toolpath/dfm/model'
130
-
131
- const curve = readReachCurve(datasheet) // null where the feature has none
132
- const feature = featureProfile(sheets[tag], featureType)
133
-
134
- export const Reach = () =>
135
- curve ? <ReachChart curve={curve} units="mm" feature={feature} /> : null
136
- ```
137
-
138
- `ReachChart` is as wide as its container. `ReachDrawing` is the same section
139
- with a caption and a note on how to read it, for a larger window of its own.
140
- Both stop drawing the curve half an inch past where the walls reach full
141
- height; `ReachDrawing` says so in its note.
142
-
143
- This is not the clearance overlay in `@toolpath/tool-drawing/clearance`: that
144
- draws the walls beside a cutting tool, to show whether the tool fits. This
145
- draws the walls alone.
146
-
147
- ## Feature panel
148
-
149
- `FeaturePanel` is the card a click on the part opens: every feature the face
150
- belongs to, then the details of the one being read. With several faces
151
- shift-clicked, each face's candidates sit under a letter, above a table of
152
- what each was read as. It fills what it is put in — where it sits, and
153
- whether it can be dragged, is the app's — and the app decides what a click
154
- means: which faces, which candidates in which order, which is read.
155
-
156
- ```tsx
157
- import { FeatureDetails, FeaturePanel, storageFolds } from '@toolpath/dfm'
158
- import { brokenRules, featureMeasurements, featureProfile } from '@toolpath/dfm/model'
159
-
160
- const folds = storageFolds(localStorage, 'toolpath.fold.')
161
-
162
- export const Inspector = () => (
163
- <FeaturePanel
164
- faces={[{ region, rows, selected }]}
165
- active={0}
166
- onSelect={(tag) => setSelected(tag)}
167
- onHover={setHovered}
168
- onClose={close}
169
- folds={folds}
170
- >
171
- <FeatureDetails
172
- feature={feature}
173
- units="mm"
174
- directionColor={directionHex}
175
- profile={featureProfile(sheets[key], feature.featureType)}
176
- required={check.required.has(key)}
177
- onFrame={() => frame(feature.tag)}
178
- rules={brokenRules(check, feature.tag, 'mm')}
179
- measurements={{
180
- status: 'ready',
181
- value: featureMeasurements({ features, feature, sheets, units: 'mm' }),
182
- }}
183
- record={{ status: 'ready', value: records[key] ?? null }}
184
- PopOut={AppWindow}
185
- folds={folds}
186
- />
187
- </FeaturePanel>
188
- )
189
- ```
190
-
191
- The parts work alone too. An app with an inspect panel of its own puts
192
- `CandidateList` and `FeatureDetails` in it and fills their slots with its own
193
- controls — a folder in a row's `detail`, a Pin button in its `action`, Zoom to
194
- in the details' `actions`, a folder badge in `status`.
195
-
196
- A turned feature reads the same way: give `FeaturePanel`, `CandidateList` and
197
- `FeatureDetails` `vocabulary={TURNING_RULES}` and a stretch from
198
- `turnedStretches`, and the feature is named as a turned one — "OD groove from
199
- both ends", "Machined from both ends" — with its considerations under
200
- "Turning considerations". Milling is the default.
64
+ ## Rule-set files and the LLM prompt
201
65
 
202
- - **Rules broken** are `BrokenRule` rows: a colour, the rule's text, the figure
203
- that broke it, and optionally the limit and a note on hover. `brokenRules`
204
- builds them from this package's check; an app with a checker of its own
205
- builds them from its hits.
206
- - **Measurements** are `featureMeasurements` rows, each with how it was worked
207
- out behind an ⓘ. `inchMark` writes inches as `0.46"`.
208
- - **Reach, the datasheet fields and the raw record** read the feature's
209
- `FeatureRecord`: its report entry and datasheet as the API sent them.
210
- - **Reads take time.** `measurements` and `record` are `Loadable`. While
211
- `loading`, a section says what it is reading; on `error` it shows the app's
212
- message and a Retry, held until `retryAt`.
213
- - **The look** differs where apps want it to: `look.rules`, `look.selected` and
214
- `look.muted`. Left out, it is the CAD viewer's.
215
- - **Folds** are kept in the app's `FoldStore`; `storageFolds(storage, prefix)`
216
- builds one over a `Storage`. Without one, a section remembers only while it
217
- is mounted.
218
- - **Pop-outs** need `PopOut`, the app's window component: the panel decides
219
- what is open and fills it, and the app draws the frame. Define it at module
220
- level, and render it through a portal to the page's body: the panel's blur
221
- makes it the box a `fixed` window inside it would be placed in.
222
- - **Keys:** Escape closes the panel and the arrow keys walk the candidates. On
223
- a `CandidateList` used alone, put `candidateListKeys` on whatever holds it.
66
+ `serializeRuleSet` writes a set as one JSON file and `parseRuleSetFile` reads
67
+ one back. `llmRulePrompt(rules, vocabulary)` is a prompt that walks an LLM
68
+ through writing a set for a shop. The rule list in `@toolpath/ui` has no button
69
+ for it; an app that wants one adds it through the list's `actions`.
224
70
 
225
71
  ## Pinch points
226
72
 
227
73
  The widest tool a feature admits, standing where the feature is tightest. The
228
- data is here; the drawing is `@toolpath/viewer`'s `<ToolMarks>`, which knows
229
- nothing of datasheets:
74
+ data is here. **Drawing it is the viewer's job, and needs `@toolpath/viewer`**;
75
+ this package does not depend on it. The viewer's `<ToolMarks>` knows nothing of
76
+ datasheets:
230
77
 
231
78
  ```tsx
232
79
  import { useMemo } from 'react'
233
- import { pinchLabel, pinchMark, placePinchTool } from '@toolpath/dfm/model'
80
+ import { pinchLabel, pinchMark, placePinchTool } from '@toolpath/dfm'
234
81
  import { featureTriangles, ToolMarks, usePartContext } from '@toolpath/viewer'
235
82
 
236
83
  // A child of <EnginePart> or <PartMesh>, which gives it the part.