mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-14 11:21:18 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5165c3e75 | ||
|
|
0a336941f4 | ||
|
|
ea90f45127 | ||
|
|
c7b4e8ef84 | ||
|
|
8f1103f064 | ||
|
|
6e42a9b0ae | ||
|
|
e77ba5f672 | ||
|
|
46b3871f8d | ||
|
|
84768da6a1 | ||
|
|
bb0d8ee1c4 | ||
|
|
f32591ed64 | ||
|
|
db9917e722 | ||
|
|
cb752d38a3 | ||
|
|
5bce937d07 | ||
|
|
de3af0b7de | ||
|
|
5a427f2eb6 | ||
|
|
008ee792f6 | ||
|
|
1591423f91 | ||
|
|
7131dd30e7 | ||
|
|
84feeaa587 | ||
|
|
5c8a287b5e | ||
|
|
a0a4a33c72 | ||
|
|
02b0d2b614 | ||
|
|
0dd4b98604 | ||
|
|
a338f6ca7d | ||
|
|
e821665e4b | ||
|
|
b77b5afd49 |
@@ -0,0 +1,220 @@
|
||||
---
|
||||
name: orca-translations
|
||||
description: Use when updating, filling, reviewing or fixing OrcaSlicer translations in localization/i18n — running scripts/run_gettext --full, translating empty or new msgids in the .po catalogs, AI translation passes and their "# AI Translated" / "# Needs human review" comments, plural forms, msgctxt homonyms, and keeping catalogs consistent with the localization glossary (OrcaSlicer_WIKI localization_glossary.tsv), including adding new glossary terms. Also use for msgfmt or run_gettext failures, placeholder or line-break mismatches, and reviewing a translation PR against the glossary.
|
||||
---
|
||||
|
||||
# OrcaSlicer translations
|
||||
|
||||
The UI strings live in gettext catalogs: `localization/i18n/OrcaSlicer.pot` is the template, and
|
||||
`localization/i18n/<lang>/OrcaSlicer_<lang>.po` holds each language. The `en` catalog is empty on
|
||||
purpose, so skip it. Recurring terms are fixed by the
|
||||
[localization glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/developer_reference/localization_glossary.md),
|
||||
whose source is `developer_reference/localization_glossary.tsv` in the **OrcaSlicer_WIKI** repository.
|
||||
A translation pass therefore touches two repositories: the catalogs here, and the glossary there.
|
||||
|
||||
All catalog editing goes through [`scripts/po_tool.py`](scripts/po_tool.py) (standard library only).
|
||||
It lists empty entries with the glossary terms they contain and validates each translation. It writes
|
||||
only the entries it changes, in the layout `msgmerge --no-wrap` produces, and adds the AI comments.
|
||||
Run commands from the repository root, with `python3` (`python` or `py -3` on Windows):
|
||||
|
||||
```bash
|
||||
T=.claude/skills/orca-translations/scripts/po_tool.py
|
||||
python3 $T --help
|
||||
```
|
||||
|
||||
Read [translation-rules.md](references/translation-rules.md) before translating. It holds the
|
||||
mechanical rules, how to pick words, style, and when to flag an entry for review. To find hard-coded
|
||||
English, strings that need a plural form or a context, or files missing from the extraction list, read
|
||||
[source-audit.md](references/source-audit.md); that work changes C++ and comes before a translation pass.
|
||||
|
||||
## Workflow: fill every empty translation
|
||||
|
||||
Unless the user asks for something narrower, a translation pass means the steps below, in order.
|
||||
|
||||
### 1. Find the glossary
|
||||
|
||||
The tool looks for an `OrcaSlicer_WIKI` clone in `--wiki`, then `$ORCA_WIKI_DIR`, then next to this
|
||||
repository.
|
||||
- **A clone is found:** `git -C <wiki> fetch` and make sure it is on an up-to-date `main`. The tool
|
||||
notes when it reads another branch, or a clone that is behind.
|
||||
- **No clone:** the tool reads the published glossary read-only. That is enough to translate, but not
|
||||
to add terms (see step 3).
|
||||
|
||||
### 2. Run the full gettext
|
||||
|
||||
This comes first, always. It regenerates the template from the sources and merges it into every
|
||||
catalog:
|
||||
|
||||
```bash
|
||||
./scripts/run_gettext.sh --full # Linux/macOS: needs gettext and python3 on PATH
|
||||
scripts\run_gettext.bat --full # Windows (PowerShell: & .\scripts\run_gettext.bat --full)
|
||||
```
|
||||
|
||||
It must exit 0. New msgids arrive empty, and removed ones become obsolete `#~` entries. A msgid that
|
||||
comes back gets its old translation revived from `#~`, which is one reason never to purge obsolete
|
||||
entries. It also compiles the `.mo` files (gitignored). The bundled Windows gettext may re-wrap a long
|
||||
`#:` reference line. That churn is harmless.
|
||||
|
||||
Then take stock: `python3 $T status`.
|
||||
|
||||
### 3. Settle new glossary terms before translating anything
|
||||
|
||||
Terms are decided once, for every language, so all the catalogs agree.
|
||||
|
||||
1. `python3 $T candidates` lists recurring phrases in the empty entries that the glossary lacks. Read it
|
||||
together with the new msgids themselves.
|
||||
2. Pick the real terms: feature and mode names, labels that tooltips repeat, and anything translators
|
||||
would otherwise render in several ways.
|
||||
3. Brand names and acronyms belong in the glossary page's hand-written *Kept in English* table instead.
|
||||
4. Skip ordinary words.
|
||||
5. For each term, choose a rendering per language: check `lookup` for existing usage, and follow each
|
||||
language's conventions. Then record it:
|
||||
|
||||
```bash
|
||||
python3 $T glossary-set --term "Belt printer" \
|
||||
--description "One sentence saying what it is, and what it is not." \
|
||||
--set de=... --set es=... --set pt_BR=...
|
||||
```
|
||||
|
||||
The command adds or updates the row, keeps the TSV's BOM and line endings, and regenerates the page.
|
||||
- **An established cell:** it refuses to change it without `--replace`. Changing an established term
|
||||
also means fixing every catalog entry that uses it, so do that only on request.
|
||||
- **An empty cell:** fill it the same way when a pending string establishes the term for that
|
||||
language.
|
||||
|
||||
**No clone, and a new term is needed: stop.** Tell the user the glossary must be updated with these
|
||||
terms, and list each one with its description and proposed renderings (`glossary-set` prints them too).
|
||||
Ask them to clone `https://github.com/OrcaSlicer/OrcaSlicer_WIKI` next to this repository, or to give
|
||||
its path. Translate nothing that uses those terms until they answer.
|
||||
|
||||
### 4. Translate, language by language, in batches
|
||||
|
||||
For each language:
|
||||
|
||||
1. Read its glossary column and notes once: `python3 $T glossary --lang <L>`.
|
||||
2. Loop over the empty entries:
|
||||
|
||||
```bash
|
||||
python3 $T pending --lang <L> --limit 60 --out <scratch>/<L>.json
|
||||
# write <scratch>/<L>-tr.json: [{"id": "...", "msgstr": "..."}, ...], "msgstr_plural" for plurals,
|
||||
# plus "review": "<what to check>" where unsure
|
||||
python3 $T apply --lang <L> --input <scratch>/<L>-tr.json
|
||||
```
|
||||
|
||||
- **Batch files go in a scratch directory, not the repository.**
|
||||
- **Each entry's `id` identifies it,** so the translation file need not repeat the English. `apply`
|
||||
also accepts `msgid` with `msgctxt`, or the pending file itself with its `msgstr` fields filled.
|
||||
- **Translate every entry in the batch.** A blank `msgstr` is skipped, not cleared.
|
||||
- **Next batch:** applied entries leave the list, so run `pending` again at offset 0. Use `--offset`
|
||||
only to step past entries you deliberately leave blank.
|
||||
- **What each entry carries:**
|
||||
- `glossary`: the terms it contains, with the language's rendering.
|
||||
- `note`: the developer's `TRN` comment.
|
||||
- `flags`: `c-format` or `boost-format`.
|
||||
- `description`: present when a sense has to be chosen.
|
||||
3. Read every apply message:
|
||||
- **REJECTED:** a hard rule broke. Fix the translation and apply the corrected items again.
|
||||
- **WARNING:** something worth a second look, such as a glossary rendering not found, ending
|
||||
punctuation, or snake_case. A glossary warning on an inflected form you checked is fine.
|
||||
Otherwise correct the translation (`apply --overwrite` replaces your own entry), or add a
|
||||
`review` reason.
|
||||
|
||||
`apply` adds `# AI Translated` to every entry it writes, and `# Needs human review: <reason>` where an
|
||||
item has `review`. On an `--overwrite`, `"review": ""` removes an earlier note. Never add either to a translation a person wrote. `--human` is for applying their
|
||||
text.
|
||||
|
||||
**The work is large:** every new string, times every language. When subagents are available, give each
|
||||
one a language or a few. Each agent only touches its own catalogs, so they can run
|
||||
in parallel. Settle step 3 first. Give each agent the language list, this skill's path, the rules file,
|
||||
and these instructions:
|
||||
- Fill every empty entry.
|
||||
- Don't add glossary rows.
|
||||
- Report what it could not translate, the review notes it added, and any term it thinks the glossary
|
||||
still lacks.
|
||||
|
||||
Add the terms they report yourself, then have the affected languages revisit the entries.
|
||||
|
||||
### 5. Verify
|
||||
|
||||
```bash
|
||||
python3 $T check --lang <L> --warnings # every AI-translated entry, plus msgfmt --check-format
|
||||
```
|
||||
|
||||
- **Run the full gettext again.** It must exit 0 and leave the catalogs as the pass left them.
|
||||
- **Run `python generate_glossary.py --check` in the wiki clone.**
|
||||
- **Errors on entries you didn't write predate the pass.** Report them rather than fixing them in the
|
||||
same change.
|
||||
|
||||
### 6. Report
|
||||
|
||||
Report:
|
||||
- the entries filled, per language;
|
||||
- the review notes added;
|
||||
- anything left empty, and why;
|
||||
- the glossary rows added or filled.
|
||||
|
||||
The catalogs (and `OrcaSlicer.pot`) and the glossary (`localization_glossary.tsv` and `.md`) are
|
||||
separate changes in separate repositories. The wiki change should land with, or before, the catalog
|
||||
change. Commit or open PRs only when asked.
|
||||
|
||||
## Rules
|
||||
|
||||
1. **Run the full gettext first.** Translate against the regenerated template, never a stale one.
|
||||
2. **The glossary is binding.** Use the language's rendering for each term, in the right sense. When a
|
||||
rendering looks wrong, use it and flag the entry. Then raise the change with the user, rather than
|
||||
deviating in one string.
|
||||
3. **New recurring terms go into the glossary before the translations that use them.** Without a wiki
|
||||
clone, stop and tell the user (step 3).
|
||||
4. **Fill, don't rewrite.** A fill pass writes only empty and fuzzy entries.
|
||||
- Existing translations, human or AI, change only on request (`--overwrite`).
|
||||
- A glossary violation in a human translation is reported, not changed.
|
||||
5. **Machine output is labelled.** Every AI translation gets `# AI Translated`; uncertain ones also get
|
||||
`# Needs human review: <reason>`. Never use `fuzzy`.
|
||||
6. **Never edit `msgid`, `msgctxt`, the header, or obsolete `#~` entries,** and never fix the English in
|
||||
a translation. Report source problems (see the rules file).
|
||||
7. **Write catalogs only through `po_tool.py` or gettext.** PO libraries such as polib reflow unrelated
|
||||
entries, and hand edits skip the validation.
|
||||
|
||||
## Changing an established term
|
||||
|
||||
A glossary cell is usually copied from the catalog's own label. When the label is wrong, the glossary
|
||||
inherits the mistake, so fix both in the same change:
|
||||
|
||||
1. **Check the catalog's usage first.** `lookup --lang <L> "<term>"` searches the English, and with
|
||||
`--msgstr` it searches the translations.
|
||||
- When most entries already use the correct form, move the cell to it.
|
||||
- When the wrong form is used consistently throughout, leave both as they are and ask a
|
||||
translator.
|
||||
2. **Update the cell:** `glossary-set --term "<Term>" --replace --set <L>=<value>`.
|
||||
3. **Rewrite the entries that still use the old form,** only where the term has that meaning.
|
||||
- Write `[{"id": "<id from lookup>", "msgstr": "<full corrected text>"}]` and run
|
||||
`apply --overwrite`.
|
||||
- The rewritten entries are marked `# AI Translated`.
|
||||
|
||||
## Reviewing a translation change
|
||||
|
||||
Review it for these:
|
||||
- glossary compliance (`check --scope all --warnings` on the language, then read the hits);
|
||||
- placeholders and line breaks (`check` errors);
|
||||
- `# AI Translated` kept on text a person rewrote, or added to text a person wrote;
|
||||
- purged obsolete entries;
|
||||
- reflowed unrelated entries;
|
||||
- plural forms short of `nplurals`.
|
||||
|
||||
When a reviewer disputes a term, compare it with the glossary first. A machine translation that follows
|
||||
the glossary is correct even if the term itself is debatable. Then the fix is a glossary change, made
|
||||
with the translators, followed by the catalogs.
|
||||
|
||||
## Source of truth
|
||||
|
||||
When this skill and the checkouts disagree, the checkouts win:
|
||||
- `scripts/run_gettext.sh` / `.bat` for extraction and merging;
|
||||
- `localization/i18n/list.txt` for the scanned sources;
|
||||
- the wiki's `localization_guide.md` and `localization_glossary.md` / `.tsv` for the rules and terms;
|
||||
- `AGENTS.md` (Localization & translations) for the repository's conventions.
|
||||
|
||||
## Editing this skill
|
||||
|
||||
State rules and procedures, not the state of the catalogs: no counts, lists of untranslated strings or
|
||||
per-language defects. Language-specific terminology belongs in the glossary's *Language specifics*
|
||||
section, not here.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Auditing the source for translatable text
|
||||
|
||||
Use this when asked to find hard-coded English, strings that need a context, or strings that need plural
|
||||
forms. It changes C++ and the `.pot`, so it runs before a translation pass and is followed by one.
|
||||
|
||||
## How a string reaches translators
|
||||
|
||||
- `xgettext` reads only the files named in `localization/i18n/list.txt`, and only the macros
|
||||
`L`, `_L`, `_u8L`, `L_CONTEXT`, `_L_CONTEXT`, `_u8L_CONTEXT` and `_L_PLURAL`.
|
||||
- A file that marks strings but is missing from `list.txt` is silently never extracted. Find such
|
||||
files by comparing `grep -l` for the macros with the list.
|
||||
- `_()`, `_utf8()` and `wxGetTranslation()` do not extract. Calls that rely on them need an `L()`
|
||||
or `_L()` somewhere xgettext sees.
|
||||
- **GUI code:** `_L` gives a `wxString`, `_u8L` a UTF-8 `std::string` (use it for ImGui). `L` only
|
||||
marks the string; the display site must translate it.
|
||||
- **libslic3r:** the macro is whatever the file defines. Some files `#define L(s)
|
||||
Slic3r::I18N::translate(s)`, so `L()` translates at runtime there. Others, such as `PrintConfig.cpp`,
|
||||
define it as a no-op marker, and the GUI translates the text later. Read the top of the file before
|
||||
judging a `format(L(...))` call. libslic3r has no plural or context lookup at runtime.
|
||||
- The libslic3r translate callback is installed in `GUI_App::on_init_inner`. Text produced before it
|
||||
is installed stays in English.
|
||||
|
||||
## What to look for
|
||||
|
||||
1. **Visible English with no macro:** labels, tooltips, menu items, dialog text, notifications and
|
||||
ImGui text. `scripts/find_untranslated.py OUT_DIR` lists candidates; most are noise, so trace each
|
||||
one to the place it is shown.
|
||||
2. **Sentences built from translated pieces:** `_L("A") + name + _L(" is B")`, or a translated word
|
||||
spliced into another sentence. Translators cannot reorder or inflect these. Replace each with one
|
||||
msgid with placeholders. A spliced fragment with a leading or trailing space is the usual sign.
|
||||
3. **Counts next to words that must agree:** `(s)`, "%d objects", a verb that follows a number. Use
|
||||
`_L_PLURAL(singular, plural, n)`. If the singular and plural are identical on purpose, translators
|
||||
still inflect each form.
|
||||
4. **One English word with several meanings:** a short msgid used in files with different meanings
|
||||
(a verb in one place, a noun in another, a mode name, a CAD term). Generate locations with
|
||||
`xgettext` *without* `--no-location` and list short msgids that occur in two or more files.
|
||||
5. **Code that compares translated text with English,** or decides behaviour from a message text.
|
||||
Translation breaks it. Compare ids or flags instead.
|
||||
6. **Tests that quote message text:** `grep` the tests for a message before rewording it.
|
||||
|
||||
## What not to translate
|
||||
|
||||
Keys, config values and identifiers; log and debug output; assertion and check messages; developer-only
|
||||
UI behind debug switches; undo/redo snapshot names (the history is never shown); text returned to a
|
||||
plugin's code; HTML, JS and desktop-file content in string literals; brand, printer-model and format
|
||||
names.
|
||||
|
||||
## Adding a context
|
||||
|
||||
- Keep the most common sense without a context, so its existing translations stay valid. Give the
|
||||
other senses a short, readable context.
|
||||
- A context cannot be carried through code that translates generically: enum labels that
|
||||
`Field.cpp` translates with `_()`, tables translated by a loop, and anything in libslic3r. Leave that
|
||||
sense on the plain entry and give the contexts to the other uses.
|
||||
|
||||
## After the edits
|
||||
|
||||
1. Build and run the tests (`libslic3r_tests` in particular).
|
||||
2. Run `run_gettext --full`. Reworded strings become new empty entries and the old ones become
|
||||
obsolete, which keeps their translations as a memory. Strings that gain a plural form leave a fuzzy
|
||||
entry.
|
||||
3. Run the translation pass from SKILL.md. `po_tool.py pending` suggests the closest earlier translation
|
||||
for each entry.
|
||||
4. Fix English typos *before* the translation pass; fixing one afterwards orphans every translation.
|
||||
@@ -0,0 +1,102 @@
|
||||
# Translation rules
|
||||
|
||||
The rules a translation must follow, condensed from the wiki's
|
||||
[Localization guide](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/developer_reference/localization_guide.md),
|
||||
the [glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/developer_reference/localization_glossary.md)
|
||||
and the localization section of `AGENTS.md`. `po_tool.py apply` rejects the mechanical violations it
|
||||
can detect; everything else is on the translator.
|
||||
|
||||
## Mechanical: enforced by `apply`
|
||||
|
||||
A rejected entry is not written. Fix it and apply again.
|
||||
|
||||
- **Placeholders stay exactly as written:** `%s`, `%d`, `%.1f`, `%1$d`, `%1%`, `%%`. Never `%1 %`, never
|
||||
`%` for `%%`. Plain printf placeholders keep their order; only positional ones (`%1$s`, `%1%`) may move.
|
||||
A broken placeholder crashes the app.
|
||||
- **Line breaks:** the same number of `\n`, with the same leading and trailing ones. Don't add breaks to fit
|
||||
text, least of all in parameter names.
|
||||
- **Leading and trailing spaces** are kept. A leading space usually means the string is appended to another.
|
||||
- **HTML tags** are kept, and the text between them is translated: `Click <a>here</a> to install it.`
|
||||
- **`℃`** (U+2103) stays one character, written exactly as in the source: `%d℃`, never `°C`, `° C` or
|
||||
`%d ℃`.
|
||||
- **Tokens stay verbatim:** `{placeholders}`, `[macros]`, G-code commands (`M141`, `G28`). Setting keys
|
||||
in snake_case (`use_relative_e_distances`) are flagged as warnings, because a few snake_case msgids
|
||||
are really labels (`top_front`). Keep a key unless the string uses it as a display name.
|
||||
- **Plural entries** need every form from the catalog's `Plural-Forms` header (`nplurals`: 1 for
|
||||
ja/ko/zh/th/vi, 3 for ru/cs/pl/lt, 4 for uk). Each form is really inflected for its quantity. Repeating
|
||||
one sentence is a bug in Slavic and Baltic languages, but correct in Turkish and Hungarian.
|
||||
|
||||
## Mechanical: not detectable, still required
|
||||
|
||||
- Edit only `msgstr`. Never change `msgid`, `msgctxt`, the header or another entry's text.
|
||||
- **Ending punctuation follows the source:** no added period, and no dropped one. `apply` warns.
|
||||
- Units follow the SI convention of the language: `s`, not `sec`. A parameter description holds no
|
||||
unit, because the field shows it.
|
||||
- **A button or short label holds one translation:** no alternatives in parentheses. They widen the
|
||||
control.
|
||||
- Don't use `fuzzy` for uncertainty. Fuzzy entries are hidden, and users then see English.
|
||||
|
||||
## Choosing the words
|
||||
|
||||
- **The glossary is binding.** Use the language's rendering for every glossary term the `pending`
|
||||
output lists, inflected as the sentence needs.
|
||||
- **Rows that share a base term are different senses:** `Seam` (the print seam) versus `Seam (UV)`
|
||||
(the unwrap cut), and `Instance` versus `Instance (application)`. Pick by the description.
|
||||
- **A qualified row may be a false match.** `Feature (Design)` does not apply to "features of the
|
||||
app".
|
||||
- **A cell marked ⚠ (or holding two renderings) is unsettled.** Use the form the catalog already
|
||||
uses for that sense (`lookup`), and flag the entry for review.
|
||||
- **Kept in English:** brand and product names (OrcaSlicer, Bambu Lab, Orca Cloud, AMS, Micro-Lidar),
|
||||
acronyms (FDM, LAN, HTTPS), file formats, material codes (PLA, PETG-CF), G-code, macros and variables
|
||||
stay as written. In "Adaptive Pressure Advance", only "Pressure Advance" stays English. See the
|
||||
glossary page's *Kept in English* table.
|
||||
- **Language specifics** on the glossary page (`po_tool.py glossary --lang L` prints them) override
|
||||
general habits for that language.
|
||||
- **Consistency beyond the glossary:** before translating a label, or a tooltip that names a setting,
|
||||
run `lookup` for the setting name. Quote the label's existing translation exactly, so the tooltip and
|
||||
the field match. Reuse obsolete (`#~`) entries as a translation memory.
|
||||
- **`msgctxt` separates homonyms.** `Back` in *Camera View* is the rear view, and `Back` in
|
||||
*Navigation* is the go-back button. Translate each context on its own.
|
||||
- **Overloaded English: translate the meaning.**
|
||||
- *Flow ratio* is a multiplier, *Flow Rate* is throughput, and *Flow Dynamics* is pressure
|
||||
compensation. These are three different terms.
|
||||
- *Extruder* can mean the toolhead, the feeder motor ("High extruder current on filament swap") or
|
||||
the nozzle ("all extruders must have the same diameter").
|
||||
- When a short label is ambiguous, grep `src/` for the msgid to see the widget it labels.
|
||||
- **Boilerplate stays uniform.** `Failed to connect to …`, `Are you sure you want to …?` and
|
||||
`If expressed as a %, it will be computed over …` each get one template in the language, even where
|
||||
the English varies.
|
||||
|
||||
## Style
|
||||
|
||||
- **Localize, don't translate word-for-word.** Know what the string controls before translating it.
|
||||
- **Simplify developer phrasing** when the meaning survives. *"This option determines whether
|
||||
OrcaSlicer should apply the retract reduction on infill"* reads better as *"Disable retractions while
|
||||
printing infill."* Introduce nuances in following sentences, not in one packed clause.
|
||||
- **Don't expand.** A machine translation adds no facts the English doesn't state. Expanding
|
||||
descriptions is for human translators, who can confirm the extra content.
|
||||
- **Write for both audiences:** professionals and people with a printer at home. Keep the established
|
||||
terminology, used as plainly as the string allows.
|
||||
|
||||
## When to add a review note
|
||||
|
||||
Add `"review": "<what to check>"` to an item when the translation is probable but unconfirmed. It
|
||||
becomes `# Needs human review: …`, and the entry still ships. Typical reasons:
|
||||
|
||||
- The English is ambiguous out of context: "Tile" as a verb or a noun.
|
||||
- A short label's role only shows in the app.
|
||||
- Two established terms compete, or the glossary cell is unsettled.
|
||||
- The string's grammar depends on a value substituted at runtime: `%zu %s` counts with no plural entry.
|
||||
|
||||
Say exactly what to look at and where: *"Row name in the Design tab tool-offer menu; check it reads
|
||||
right for the whole row."*
|
||||
|
||||
## Problems that belong in the source, not the translation
|
||||
|
||||
Report these; don't work around them in a catalog.
|
||||
|
||||
- **The English is wrong.** Never "fix" it in the translation only.
|
||||
- **One msgid needs two translations.** The source needs `_L_CONTEXT` / `_u8L_CONTEXT` (a code change).
|
||||
- **A literal `%` in a string xgettext flagged `possible-c-format`** fails `msgfmt`. The fix is a
|
||||
`// xgettext:no-c-format, no-boost-format` comment above the string in the source, not `%%` in the
|
||||
translation.
|
||||
@@ -0,0 +1,113 @@
|
||||
"""List C++ string literals that look like user-facing English but are not marked for translation.
|
||||
|
||||
Usage: find_untranslated.py OUT_DIR (one hits file per source area; each line is file:line: [call] "text" | code)
|
||||
Works on whole files, so literals continuing a translation macro call from an earlier line are
|
||||
recognised. Skips comments, log/assert/check calls, includes, printer model lists and markup."""
|
||||
import re, sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[4]
|
||||
OUT = Path(sys.argv[1]); OUT.mkdir(parents=True, exist_ok=True)
|
||||
MACROS = {"_L", "_u8L", "L", "_L_CONTEXT", "_u8L_CONTEXT", "L_CONTEXT", "_L_PLURAL", "_devL", "_omitL",
|
||||
"_CHB", "_utf8", "_", "translate", "translate_utf8", "wxGetTranslation", "T"}
|
||||
NOISE_CALLS = {"BOOST_LOG_TRIVIAL", "wxCHECK", "wxCHECK_MSG", "wxCHECK_RET", "wxASSERT", "wxASSERT_MSG", "wxFAIL_MSG",
|
||||
"assert", "static_assert", "printf", "fprintf", "sprintf", "snprintf", "wxLogDebug", "wxLogTrace",
|
||||
"wxLogMessage", "wxLogError", "wxLogWarning", "OutputDebugStringA", "OutputDebugStringW", "DEBUG_LOG",
|
||||
"glsafe", "GLShaderProgram", "find", "count", "contains", "starts_with", "ends_with", "get_value",
|
||||
"has", "opt_bool", "opt_int", "opt_float", "opt_string", "option", "get", "set_key_value", "at",
|
||||
"boost_log", "LOGD", "LOGE", "LOGI", "LOGW", "SPDLOG", "CLI_LOG"}
|
||||
LIT = re.compile(r'"((?:[^"\\\n]|\\.)*)"')
|
||||
WORD = re.compile(r"[A-Za-z]{2,}")
|
||||
|
||||
def strip_comments(text):
|
||||
# Replace comments with spaces, keeping offsets and string literals intact.
|
||||
out, i, n = [], 0, len(text)
|
||||
while i < n:
|
||||
c = text[i]
|
||||
if c == '"' or c == "'":
|
||||
j = i + 1
|
||||
while j < n and text[j] != c and text[j] != "\n":
|
||||
j += 2 if text[j] == "\\" else 1
|
||||
out.append(text[i:j + 1]); i = j + 1
|
||||
elif text.startswith("//", i):
|
||||
j = text.find("\n", i); j = n if j < 0 else j
|
||||
out.append(" " * (j - i)); i = j
|
||||
elif text.startswith("/*", i):
|
||||
j = text.find("*/", i + 2); j = n if j < 0 else j + 2
|
||||
out.append(re.sub(r"[^\n]", " ", text[i:j])); i = j
|
||||
else:
|
||||
out.append(c); i += 1
|
||||
return "".join(out)
|
||||
|
||||
def enclosing_call(text, pos):
|
||||
depth = 0
|
||||
i = pos - 1
|
||||
while i >= 0:
|
||||
c = text[i]
|
||||
if c == '"': # skip over a literal backwards
|
||||
i -= 1
|
||||
while i >= 0 and not (text[i] == '"' and text[i - 1] != "\\"):
|
||||
i -= 1
|
||||
elif c in ")]}":
|
||||
depth += 1
|
||||
elif c in "([{":
|
||||
if depth == 0:
|
||||
if c != "(":
|
||||
return None
|
||||
m = re.search(r"([A-Za-z_][\w:]*)\s*$", text[max(0, i - 80):i])
|
||||
return m.group(1).split("::")[-1] if m else None
|
||||
depth -= 1
|
||||
elif c == ";" and depth == 0:
|
||||
return None
|
||||
i -= 1
|
||||
return None
|
||||
|
||||
def looks_user_facing(s):
|
||||
if len(WORD.findall(s)) < 2 and not re.fullmatch(r"[A-Z][a-z]{2,}[.!?:]?", s):
|
||||
return False
|
||||
if " " not in s and re.fullmatch(r"[\w./\\:#%-]+", s):
|
||||
return False
|
||||
if re.search(r"https?://|<\w+[^>]*>|\.(png|svg|json|ini|3mf|stl|gcode|bbl|js|html|css|txt|xml|zip)\b|=\s*\w+;|^\s*[-\w]+\s*:\s*[\w#]", s):
|
||||
return False
|
||||
if re.fullmatch(r"[a-z0-9_ ]+", s) and "_" in s:
|
||||
return False
|
||||
return bool(re.search(r"[A-Za-z]{2,} [a-z]{2,}|^[A-Z][a-z]{2,}", s))
|
||||
|
||||
groups = {}
|
||||
for path in sorted((REPO / "src").rglob("*.[ch]pp")):
|
||||
rel = path.relative_to(REPO).as_posix()
|
||||
if "/dev-utils/" in rel or "/libvgcode/" in rel or rel.startswith("src/libnest2d") or "/tests/" in rel:
|
||||
continue
|
||||
raw = path.read_text(encoding="utf-8", errors="replace")
|
||||
text = strip_comments(raw)
|
||||
line_starts = [0] + [m.end() for m in re.finditer("\n", text)]
|
||||
lines = raw.splitlines()
|
||||
hits = []
|
||||
for m in LIT.finditer(text):
|
||||
s = m.group(1)
|
||||
if not looks_user_facing(s):
|
||||
continue
|
||||
call = enclosing_call(text, m.start())
|
||||
if call in MACROS or call in NOISE_CALLS:
|
||||
continue
|
||||
ln = next(k for k in range(len(line_starts) - 1, -1, -1) if line_starts[k] <= m.start()) + 1
|
||||
src = lines[ln - 1].strip()
|
||||
if re.search(r"BOOST_LOG|#\s*include|<<\s*\"|\"\s*<<|std::cerr|std::cout", src):
|
||||
continue
|
||||
# printer model / vendor tables
|
||||
if len(LIT.findall(src)) >= 4 and not re.search(r"_L|_u8L", src):
|
||||
continue
|
||||
hits.append(f"{rel}:{ln}: [{call or '-'}] \"{s[:150]}\" | {src[:170]}")
|
||||
if hits:
|
||||
parts = rel.split("/")
|
||||
if parts[1] == "slic3r":
|
||||
key = f"GUI/{parts[3] if len(parts) > 4 else 'root'}" if parts[2] == "GUI" else f"slic3r/{parts[2]}"
|
||||
else:
|
||||
key = parts[1].replace(".cpp", "")
|
||||
groups.setdefault(key, []).extend(hits)
|
||||
total = 0
|
||||
for key, hits in sorted(groups.items()):
|
||||
(OUT / (key.replace("/", "_") + ".txt")).write_text("\n".join(hits) + "\n", encoding="utf-8")
|
||||
total += len(hits)
|
||||
print(f"{len(hits):5} {key}")
|
||||
print("total", total)
|
||||
@@ -0,0 +1,870 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Translation helper for the OrcaSlicer gettext catalogs and the wiki glossary.
|
||||
|
||||
Standard library only. Edits a catalog in place, rewriting just the entries it
|
||||
changes in the layout `msgmerge --no-wrap` writes, so every other byte stays put.
|
||||
|
||||
status [--lang L ...] per-catalog counts
|
||||
pending --lang L [--offset N --limit N] [--out FILE] [--no-include-fuzzy] (adds similar earlier translations)
|
||||
apply --lang L --input FILE [--overwrite] [--dry-run] adds "# AI Translated"
|
||||
check [--lang L ...] [--scope ai|all] [--warnings]
|
||||
lookup --lang L PATTERN [--msgstr] existing translations with ids, obsolete ones included
|
||||
glossary --lang L [TERM] the language's glossary column and notes
|
||||
candidates [--min-count N] [--limit N] recurring untranslated phrases not in the glossary
|
||||
glossary-set --term T [--description D] --set L=VALUE ... [--replace]
|
||||
|
||||
The glossary is read from an OrcaSlicer_WIKI clone (--wiki, $ORCA_WIKI_DIR, or a
|
||||
sibling of this repository). Without one it is downloaded read-only, and
|
||||
glossary-set refuses to run.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import unicodedata
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[4]
|
||||
I18N = REPO / "localization" / "i18n"
|
||||
SKIP_LANGS = {"en"} # the English catalog is intentionally empty
|
||||
GLOSSARY_TSV = Path("developer_reference") / "localization_glossary.tsv"
|
||||
GLOSSARY_MD = Path("developer_reference") / "localization_glossary.md"
|
||||
MISSING = {"", "—"}
|
||||
RAW_URL = "https://raw.githubusercontent.com/OrcaSlicer/OrcaSlicer_WIKI/main/"
|
||||
AI_TAG = "AI Translated"
|
||||
REVIEW_TAG = "Needs human review:"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PO parsing and writing
|
||||
|
||||
_UNESCAPE = {"n": "\n", "t": "\t", "r": "\r", "a": "\a", "b": "\b", "f": "\f", "v": "\v", '"': '"', "\\": "\\"}
|
||||
_ESCAPE = {v: "\\" + k for k, v in _UNESCAPE.items()}
|
||||
|
||||
|
||||
def unescape(s):
|
||||
return re.sub(r'\\(.)', lambda m: _UNESCAPE.get(m.group(1), m.group(0)), s)
|
||||
|
||||
|
||||
def escape(s):
|
||||
return "".join(_ESCAPE.get(c, c) for c in s)
|
||||
|
||||
|
||||
def format_field(keyword, value, prefix=""):
|
||||
"""Lines for `keyword "value"` as msgmerge --no-wrap writes them."""
|
||||
parts = value.split("\n")
|
||||
segments = [p + "\n" for p in parts[:-1]] + ([parts[-1]] if parts[-1] else [])
|
||||
if len(segments) <= 1:
|
||||
return [f'{prefix}{keyword} "{escape(value)}"']
|
||||
return [f'{prefix}{keyword} ""'] + [f'{prefix}"{escape(s)}"' for s in segments]
|
||||
|
||||
|
||||
class Entry:
|
||||
"""One blank-line-delimited block of a PO file."""
|
||||
|
||||
def __init__(self, lines, first_line):
|
||||
self.lines = lines
|
||||
self.first_line = first_line # 0-based index in the file
|
||||
self.obsolete = all(l.startswith("#~") for l in lines if not l.startswith("#") or l.startswith("#~"))
|
||||
self.tcomments, self.xcomments, self.flags = [], [], []
|
||||
self.fields = {} # keyword -> [value, start, end)
|
||||
self.order = []
|
||||
current = None
|
||||
for i, raw in enumerate(lines):
|
||||
line = raw
|
||||
if self.obsolete and line.startswith("#~"):
|
||||
line = line[2:].lstrip(" ")
|
||||
if line.startswith("|"):
|
||||
current = None
|
||||
continue
|
||||
elif line.startswith("#"):
|
||||
current = None
|
||||
if line.startswith("#."):
|
||||
self.xcomments.append(line[2:].strip())
|
||||
elif line.startswith("#,"):
|
||||
self.flags += [f.strip() for f in line[2:].split(",") if f.strip()]
|
||||
elif line == "#" or line.startswith("# "):
|
||||
self.tcomments.append(line[2:])
|
||||
continue
|
||||
m = re.match(r'^(msgctxt|msgid_plural|msgid|msgstr(?:\[\d+\])?)\s+"(.*)"\s*$', line)
|
||||
if m:
|
||||
current = m.group(1)
|
||||
self.fields[current] = [unescape(m.group(2)), i, i + 1]
|
||||
self.order.append(current)
|
||||
elif line.startswith('"') and current:
|
||||
self.fields[current][0] += unescape(line.strip()[1:-1])
|
||||
self.fields[current][2] = i + 1
|
||||
|
||||
def get(self, key, default=None):
|
||||
f = self.fields.get(key)
|
||||
return f[0] if f else default
|
||||
|
||||
@property
|
||||
def msgctxt(self):
|
||||
return self.get("msgctxt")
|
||||
|
||||
@property
|
||||
def msgid(self):
|
||||
return self.get("msgid", "")
|
||||
|
||||
@property
|
||||
def msgid_plural(self):
|
||||
return self.get("msgid_plural")
|
||||
|
||||
@property
|
||||
def is_header(self):
|
||||
return self.msgid == "" and "msgid" in self.fields and not self.msgctxt
|
||||
|
||||
def msgstrs(self):
|
||||
if self.msgid_plural is None:
|
||||
return [self.get("msgstr", "")]
|
||||
idx = sorted(int(k[7:-1]) for k in self.fields if k.startswith("msgstr["))
|
||||
return [self.get(f"msgstr[{i}]", "") for i in range(max(idx) + 1)] if idx else []
|
||||
|
||||
@property
|
||||
def fuzzy(self):
|
||||
return "fuzzy" in self.flags
|
||||
|
||||
@property
|
||||
def ai(self):
|
||||
return any(c.strip() == AI_TAG for c in self.tcomments)
|
||||
|
||||
@property
|
||||
def review(self):
|
||||
return [c for c in self.tcomments if c.startswith(REVIEW_TAG)]
|
||||
|
||||
def key(self):
|
||||
return (self.msgctxt, self.msgid)
|
||||
|
||||
def id(self):
|
||||
"""Short stable handle, so a translation file need not repeat the English."""
|
||||
return hashlib.sha1(f"{self.msgctxt or ''}\x04{self.msgid}".encode("utf-8")).hexdigest()[:10]
|
||||
|
||||
def rewrite(self, msgstrs, ai=True, review=None):
|
||||
"""Replace the translation; add the AI and review comments; clear fuzzy."""
|
||||
lines = list(self.lines)
|
||||
# translations
|
||||
keys = [k for k in self.order if k.startswith("msgstr")]
|
||||
start = min(self.fields[k][1] for k in keys)
|
||||
end = max(self.fields[k][2] for k in keys)
|
||||
if self.msgid_plural is None:
|
||||
new = format_field("msgstr", msgstrs[0])
|
||||
else:
|
||||
new = [l for i, s in enumerate(msgstrs) for l in format_field(f"msgstr[{i}]", s)]
|
||||
lines[start:end] = new
|
||||
# flags and previous-msgid lines of a fuzzy entry
|
||||
out = []
|
||||
for line in lines:
|
||||
if line.startswith("#,"):
|
||||
flags = [f.strip() for f in line[2:].split(",") if f.strip() and f.strip() != "fuzzy"]
|
||||
if flags:
|
||||
out.append("#, " + ", ".join(flags))
|
||||
continue
|
||||
if line.startswith("#|") and self.fuzzy:
|
||||
continue
|
||||
out.append(line)
|
||||
lines = out
|
||||
# translator comments go first, before #. #: #,
|
||||
pos = 0
|
||||
while pos < len(lines) and (lines[pos] == "#" or lines[pos].startswith("# ")):
|
||||
pos += 1
|
||||
add = []
|
||||
if review is not None: # "" clears an earlier note, a reason replaces it
|
||||
lines = [l for l in lines if not l.startswith("# " + REVIEW_TAG)]
|
||||
pos = 0
|
||||
while pos < len(lines) and (lines[pos] == "#" or lines[pos].startswith("# ")):
|
||||
pos += 1
|
||||
if ai and not any(l == "# " + AI_TAG for l in lines[:pos]):
|
||||
add.append("# " + AI_TAG)
|
||||
if review:
|
||||
add.append(f"# {REVIEW_TAG} {' '.join(review.split())}")
|
||||
lines[pos:pos] = add
|
||||
return lines
|
||||
|
||||
|
||||
class Catalog:
|
||||
def __init__(self, path):
|
||||
self.path = Path(path)
|
||||
data = self.path.read_bytes()
|
||||
self.bom = data.startswith(b"\xef\xbb\xbf")
|
||||
text = data.decode("utf-8-sig")
|
||||
self.newline = "\r\n" if "\r\n" in text else "\n"
|
||||
self.trailing = text.endswith(("\n", "\r"))
|
||||
self.lines = text.splitlines()
|
||||
self.entries = []
|
||||
block, first = [], 0
|
||||
for i, line in enumerate(self.lines + [""]):
|
||||
if line.strip() == "":
|
||||
if block:
|
||||
self.entries.append(Entry(block, first))
|
||||
block = []
|
||||
else:
|
||||
if not block:
|
||||
first = i
|
||||
block.append(line)
|
||||
self.header = next((e for e in self.entries if e.is_header), None)
|
||||
m = re.search(r"nplurals\s*=\s*(\d+)", self.header.msgstrs()[0] if self.header else "")
|
||||
self.nplurals = int(m.group(1)) if m else 2
|
||||
self.changes = {} # entry index -> new lines
|
||||
|
||||
def active(self):
|
||||
return [e for e in self.entries if not e.obsolete and not e.is_header]
|
||||
|
||||
def index(self):
|
||||
return {e.key(): i for i, e in enumerate(self.entries) if not e.obsolete and not e.is_header}
|
||||
|
||||
def save(self):
|
||||
lines = list(self.lines)
|
||||
for i in sorted(self.changes, reverse=True):
|
||||
e = self.entries[i]
|
||||
lines[e.first_line:e.first_line + len(e.lines)] = self.changes[i]
|
||||
text = self.newline.join(lines) + (self.newline if self.trailing else "")
|
||||
self.path.write_bytes((b"\xef\xbb\xbf" if self.bom else b"") + text.encode("utf-8"))
|
||||
|
||||
|
||||
def needs_translation(e, nplurals, include_fuzzy=False):
|
||||
strs = e.msgstrs()
|
||||
if e.msgid_plural is not None and len(strs) < nplurals:
|
||||
return True
|
||||
return any(s == "" for s in strs) or (include_fuzzy and e.fuzzy)
|
||||
|
||||
|
||||
def catalog_path(lang):
|
||||
p = I18N / lang / f"OrcaSlicer_{lang}.po"
|
||||
if not p.exists():
|
||||
sys.exit(f"no catalog for '{lang}': {p}")
|
||||
return p
|
||||
|
||||
|
||||
def all_langs():
|
||||
return sorted(d.name for d in I18N.iterdir() if (d / f"OrcaSlicer_{d.name}.po").exists() and d.name not in SKIP_LANGS)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Glossary
|
||||
|
||||
def find_wiki(arg):
|
||||
for cand in [arg, os.environ.get("ORCA_WIKI_DIR"), REPO.parent / "OrcaSlicer_WIKI", REPO.parent / "OrcaSlicer.wiki"]:
|
||||
if cand and (Path(cand) / GLOSSARY_TSV).exists():
|
||||
return Path(cand)
|
||||
return None
|
||||
|
||||
|
||||
def _download(rel):
|
||||
cache = Path(tempfile.gettempdir()) / ("orca_glossary_" + rel.name)
|
||||
if not cache.exists() or time.time() - cache.stat().st_mtime > 3600:
|
||||
with urllib.request.urlopen(RAW_URL + rel.as_posix(), timeout=30) as r:
|
||||
cache.write_bytes(r.read())
|
||||
return cache
|
||||
|
||||
|
||||
class Glossary:
|
||||
def __init__(self, wiki_arg=None, quiet=False):
|
||||
self.wiki = find_wiki(wiki_arg)
|
||||
if self.wiki:
|
||||
self.tsv, self.md = self.wiki / GLOSSARY_TSV, self.wiki / GLOSSARY_MD
|
||||
if not quiet:
|
||||
self.report_clone_state()
|
||||
else:
|
||||
if not quiet:
|
||||
print("note: no OrcaSlicer_WIKI clone found; using the published glossary read-only", file=sys.stderr)
|
||||
self.tsv, self.md = _download(GLOSSARY_TSV), _download(GLOSSARY_MD)
|
||||
self.load()
|
||||
|
||||
def report_clone_state(self):
|
||||
git = lambda *args: subprocess.run(["git", "-C", str(self.wiki), *args], capture_output=True, text=True).stdout.strip()
|
||||
try:
|
||||
branch = git("rev-parse", "--abbrev-ref", "HEAD")
|
||||
behind = git("rev-list", "--count", "HEAD..origin/main")
|
||||
except OSError:
|
||||
return
|
||||
if branch and branch != "main":
|
||||
print(f"note: glossary read from wiki branch '{branch}', not main", file=sys.stderr)
|
||||
if behind and behind != "0":
|
||||
print(f"note: the wiki clone is {behind} commits behind origin/main (as of its last fetch)", file=sys.stderr)
|
||||
|
||||
def load(self):
|
||||
rows = [l.split("\t") for l in self.tsv.read_text(encoding="utf-8-sig").splitlines() if l.strip()]
|
||||
self.header = rows[0]
|
||||
# "—" marks a language with no established rendering yet
|
||||
self.rows = [[c if c.strip() not in MISSING else "" for c in r] + [""] * (len(rows[0]) - len(r)) for r in rows[1:]]
|
||||
self.matchers = []
|
||||
for row in self.rows:
|
||||
base = re.sub(r"\s*\([^)]*\)\s*$", "", row[0]).strip()
|
||||
alts = [a.strip() for a in base.split(" / ") if a.strip()]
|
||||
pats = [re.compile(r"(?<![\w-])" + r"[\s-]+".join(map(re.escape, a.split())) + r"(?:s|es)?(?![\w-])", re.I) for a in alts]
|
||||
self.matchers.append((row, pats))
|
||||
|
||||
def column(self, lang):
|
||||
return self.header.index(lang) if lang in self.header else None
|
||||
|
||||
def matches(self, text):
|
||||
"""Glossary rows found in text, without terms only seen inside a longer match."""
|
||||
spans = []
|
||||
for row, pats in self.matchers:
|
||||
for p in pats:
|
||||
spans += [(m.start(), m.end(), row) for m in p.finditer(text)]
|
||||
keep = []
|
||||
for row in {id(r): r for _, _, r in spans}.values():
|
||||
mine = [(s, e) for s, e, r in spans if r is row]
|
||||
if any(not any(s2 <= s and e <= e2 and (e2 - s2) > (e - s) for s2, e2, r2 in spans if r2 is not row) for s, e in mine):
|
||||
keep.append(row)
|
||||
return keep
|
||||
|
||||
def hints(self, text, lang):
|
||||
col = self.column(lang)
|
||||
return [{"term": r[0], "translation": (r[col] if col is not None else "") or None, "description": r[1]} for r in self.matches(text)]
|
||||
|
||||
def language_notes(self, lang):
|
||||
text = self.md.read_text(encoding="utf-8-sig")
|
||||
m = re.search(r"^### [^\n]*\(" + re.escape(lang) + r"\)\s*$(.*?)(?=^##|\Z)", text, re.M | re.S)
|
||||
return m.group(0).strip() if m else None
|
||||
|
||||
|
||||
def _norm(s):
|
||||
s = unicodedata.normalize("NFD", s.casefold())
|
||||
return "".join(c for c in s if unicodedata.category(c) != "Mn")
|
||||
|
||||
|
||||
def glossary_ok(msgstr, translation):
|
||||
"""Loose check that a glossary rendering appears in msgstr, tolerating inflection."""
|
||||
target = _norm(msgstr)
|
||||
for alt in re.split(r"\s*/\s*", re.sub(r"\([^)]*\)|⚠", "", translation)):
|
||||
words = [w for w in re.findall(r"\w+", _norm(alt)) if len(w) > 2] or re.findall(r"\w+", _norm(alt))
|
||||
if not words:
|
||||
return True
|
||||
if all(w in target or (len(w) > 4 and w[:max(4, len(w) * 2 // 3)] in target) for w in words):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Validation
|
||||
|
||||
C_FMT = re.compile(r"%(?:(\d+)\$)?[-+ #0']*(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:hh|h|ll|l|L|q|j|z|Z|t)?[diouxXeEfFgGaAcspn]")
|
||||
BOOST_FMT = re.compile(r"%\d+%")
|
||||
TAG = re.compile(r"</?[A-Za-z][^<>]*>")
|
||||
SNAKE = re.compile(r"[a-z][a-z0-9]*(?:_[a-z0-9]+)+")
|
||||
IDENT = re.compile(r"\b[a-z][a-z0-9]*(?:_[a-z0-9]+)+\b|\b[GM]\d{1,4}\b|\{[A-Za-z_][\w.\[\]]*\}|\[[a-z_]+\]")
|
||||
END = re.compile(r"[.:?!。:?!]$")
|
||||
|
||||
|
||||
def _placeholders(s, flags):
|
||||
s = s.replace("%%", "")
|
||||
boost = BOOST_FMT.findall(s)
|
||||
s2 = BOOST_FMT.sub("", s) if "boost-format" in flags or boost else s
|
||||
c = [m.group(0) for m in C_FMT.finditer(s2)] if "no-c-format" not in flags else []
|
||||
return boost, c
|
||||
|
||||
|
||||
def validate(e, msgstrs, nplurals, glossary=None, lang=None):
|
||||
"""Return (errors, warnings) for a proposed translation of entry e."""
|
||||
errors, warnings = [], []
|
||||
flags = set(e.flags)
|
||||
if e.msgid_plural is not None and len(msgstrs) != nplurals:
|
||||
errors.append(f"plural entry needs {nplurals} forms, got {len(msgstrs)}")
|
||||
for i, s in enumerate(msgstrs):
|
||||
src = e.msgid if (e.msgid_plural is None or (i == 0 and nplurals > 1)) else e.msgid_plural
|
||||
tag = f"[{i}] " if e.msgid_plural is not None else ""
|
||||
if not s:
|
||||
errors.append(f"{tag}empty translation")
|
||||
continue
|
||||
b1, c1 = _placeholders(src, flags)
|
||||
b2, c2 = _placeholders(s, flags)
|
||||
positional = any("$" in p for p in c1)
|
||||
c_bad = sorted(c1) != sorted(c2) if positional else c1 != c2
|
||||
bad = []
|
||||
if sorted(b1) != sorted(b2):
|
||||
bad.append(f"boost placeholders {b1} -> {b2}")
|
||||
if c_bad:
|
||||
bad.append(f"printf placeholders {c1} -> {c2}" + ("" if positional else " (order must match)"))
|
||||
if bad:
|
||||
strict = flags & {"c-format", "boost-format"} and not (e.msgid_plural is not None and i == 0 and nplurals > 1 and not c2 and not b2)
|
||||
(errors if strict else warnings).extend(tag + b for b in bad)
|
||||
if s.count("%%") != src.count("%%") and "c-format" in flags:
|
||||
errors.append(f"{tag}'%%' count differs")
|
||||
if src.count("\n") != s.count("\n"):
|
||||
errors.append(f"{tag}line breaks: {src.count(chr(10))} in source, {s.count(chr(10))} in translation")
|
||||
else:
|
||||
lead = lambda t: len(t) - len(t.lstrip("\n"))
|
||||
trail = lambda t: len(t) - len(t.rstrip("\n"))
|
||||
if lead(src) != lead(s) or trail(src) != trail(s):
|
||||
errors.append(f"{tag}leading/trailing line breaks differ")
|
||||
ls = lambda t: re.match(r"[ \t]*", t.strip("\n")).group(0)
|
||||
ts = lambda t: re.search(r"[ \t]*$", t.strip("\n")).group(0)
|
||||
if ls(src) != ls(s) or ts(src) != ts(s):
|
||||
errors.append(f"{tag}leading/trailing spaces differ")
|
||||
if sorted(TAG.findall(src)) != sorted(TAG.findall(s)):
|
||||
errors.append(f"{tag}HTML tags {TAG.findall(src)} -> {TAG.findall(s)}")
|
||||
if src.count("℃") != s.count("℃"):
|
||||
errors.append(f"{tag}'℃' count differs (keep U+2103, not °C)")
|
||||
missing = [t for t in set(IDENT.findall(src)) if t not in s]
|
||||
tokens = [t for t in missing if not SNAKE.fullmatch(t)]
|
||||
if tokens:
|
||||
errors.append(f"{tag}tokens must stay verbatim: {tokens}")
|
||||
if len(tokens) < len(missing): # snake_case is usually a setting key, sometimes a label
|
||||
warnings.append(f"{tag}snake_case kept? {[t for t in missing if SNAKE.fullmatch(t)]}")
|
||||
e1, e2 = END.search(src.rstrip()), END.search(s.rstrip())
|
||||
if bool(e1) != bool(e2) and lang != "th": # Thai has no sentence-final period
|
||||
warnings.append(f"{tag}ending punctuation: source {'ends with ' + repr(e1.group(0)) if e1 else 'has none'}, translation {'ends with ' + repr(e2.group(0)) if e2 else 'has none'}")
|
||||
if s == src and len(src.split()) >= 3:
|
||||
warnings.append(f"{tag}identical to the English")
|
||||
if glossary and lang:
|
||||
# Rows sharing a base term ("Seam", "Seam (UV)") are competing senses; one is enough.
|
||||
# A match on qualified rows only ("Feature (Design)") may be another sense entirely.
|
||||
for base, senses in group_senses(glossary.hints(src, lang)).items():
|
||||
if all(h["term"] != base for h in senses) or not strong_match(src, base):
|
||||
continue
|
||||
if not any(glossary_ok(s, h["translation"]) for h in senses):
|
||||
wanted = " or ".join(f"'{h['translation']}' ({h['term']})" for h in senses)
|
||||
warnings.append(f"{tag}glossary: expected {wanted}")
|
||||
return errors, warnings
|
||||
|
||||
|
||||
def strong_match(src, base):
|
||||
"""Whether a term is surely meant as the glossary term, not as everyday English
|
||||
("each part of a frame"): a multi-word term, a short label, or capitalised mid-sentence."""
|
||||
if any(" " in alt for alt in base.split(" / ")) or len(src.split()) <= 5:
|
||||
return True
|
||||
for alt in base.split(" / "):
|
||||
for m in re.finditer(r"(?<![\w-])" + re.escape(alt) + r"(?:s|es)?(?![\w-])", src, re.I):
|
||||
if m.group(0)[0].isupper() and not re.search(r"(^|[.!?:]\s+|\n)$", src[:m.start()]):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def base_term(term):
|
||||
return re.sub(r"\s*\([^)]*\)\s*$", "", term).strip()
|
||||
|
||||
|
||||
def group_senses(hints):
|
||||
groups = {}
|
||||
for h in hints:
|
||||
if h["translation"]:
|
||||
groups.setdefault(base_term(h["term"]), []).append(h)
|
||||
return groups
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Commands
|
||||
|
||||
def out_json(obj, path):
|
||||
text = json.dumps(obj, ensure_ascii=False, indent=1)
|
||||
if path:
|
||||
Path(path).write_text(text + "\n", encoding="utf-8")
|
||||
print(f"wrote {path}")
|
||||
else:
|
||||
sys.stdout.write(text + "\n")
|
||||
|
||||
|
||||
def cmd_status(a):
|
||||
print(f"{'lang':7} {'active':>7} {'empty':>6} {'plural':>6} {'fuzzy':>6} {'AI':>6} {'review':>6}")
|
||||
for lang in a.lang or all_langs():
|
||||
c = Catalog(catalog_path(lang))
|
||||
act = c.active()
|
||||
empty = sum(1 for e in act if needs_translation(e, c.nplurals) and e.msgid_plural is None)
|
||||
plural = sum(1 for e in act if needs_translation(e, c.nplurals) and e.msgid_plural is not None)
|
||||
print(f"{lang:7} {len(act):7} {empty:6} {plural:6} {sum(e.fuzzy for e in act):6} {sum(e.ai for e in act):6} {sum(bool(e.review) for e in act):6}")
|
||||
|
||||
|
||||
def similar_entries(c, e, pool, cutoff=0.72):
|
||||
"""The closest earlier translation of a similar English text: obsolete entries and translated
|
||||
active ones. A reworded or split string usually still has one, and reusing it keeps the wording."""
|
||||
import difflib
|
||||
sm = difflib.SequenceMatcher(autojunk=False)
|
||||
sm.set_seq2(e.msgid)
|
||||
best = []
|
||||
for other, msgstr, obsolete in pool:
|
||||
sm.set_seq1(other)
|
||||
if sm.real_quick_ratio() < cutoff or sm.quick_ratio() < cutoff:
|
||||
continue
|
||||
r = sm.ratio()
|
||||
if r >= cutoff and other != e.msgid:
|
||||
best.append((r, other, msgstr, obsolete))
|
||||
best.sort(key=lambda t: -t[0])
|
||||
return [{"msgid": o, "msgstr": s, "obsolete": ob, "similarity": round(r, 2)} for r, o, s, ob in best[:2]]
|
||||
|
||||
|
||||
def cmd_pending(a):
|
||||
c = Catalog(catalog_path(a.lang))
|
||||
g = Glossary(a.wiki)
|
||||
todo = [e for e in c.active() if needs_translation(e, c.nplurals, a.include_fuzzy)]
|
||||
batch = todo[a.offset:a.offset + a.limit] if a.limit else todo[a.offset:]
|
||||
pool = [(x.msgid, x.msgstrs()[0], x.obsolete) for x in c.entries
|
||||
if not x.is_header and x.msgstrs() and x.msgstrs()[0] and not x.fuzzy and 8 < len(x.msgid) < 600]
|
||||
items = []
|
||||
for e in batch:
|
||||
item = {"id": e.id(), "msgctxt": e.msgctxt, "msgid": e.msgid}
|
||||
if e.msgid_plural is not None:
|
||||
item["msgid_plural"] = e.msgid_plural
|
||||
item["msgstr_plural"] = (e.msgstrs() + [""] * c.nplurals)[:c.nplurals]
|
||||
else:
|
||||
item["msgstr"] = e.msgstrs()[0]
|
||||
if e.xcomments:
|
||||
item["note"] = " ".join(e.xcomments)
|
||||
flags = [f for f in e.flags if f != "fuzzy"]
|
||||
if flags:
|
||||
item["flags"] = flags
|
||||
if e.fuzzy:
|
||||
item["fuzzy"] = True
|
||||
if e.msgstrs()[0]:
|
||||
item["previous_translation"] = e.msgstrs()[0]
|
||||
if len(e.msgid) > 8:
|
||||
sim = similar_entries(c, e, pool)
|
||||
if sim:
|
||||
item["similar"] = sim
|
||||
hints = g.hints(e.msgid + "\n" + (e.msgid_plural or ""), a.lang)
|
||||
if hints:
|
||||
# Descriptions only where the sense must be chosen or no rendering exists yet.
|
||||
bases = [base_term(h["term"]) for h in hints]
|
||||
item["glossary"] = [{k: v for k, v in h.items() if k != "description" or not h["translation"] or bases.count(b) > 1 or b != h["term"]}
|
||||
for h, b in zip(hints, bases)]
|
||||
items.append({k: v for k, v in item.items() if v is not None})
|
||||
out_json({"lang": a.lang, "nplurals": c.nplurals, "plural_forms": re.search(r"Plural-Forms: ([^\n]*)", c.header.msgstrs()[0]).group(1) if c.header else None,
|
||||
"total_pending": len(todo), "offset": a.offset, "count": len(items), "entries": items}, a.out)
|
||||
|
||||
|
||||
def cmd_apply(a):
|
||||
c = Catalog(catalog_path(a.lang))
|
||||
g = None if a.no_glossary else Glossary(a.wiki, quiet=True)
|
||||
data = json.loads(Path(a.input).read_text(encoding="utf-8"))
|
||||
items = data["entries"] if isinstance(data, dict) else data
|
||||
idx = c.index()
|
||||
by_id = {c.entries[i].id(): i for i in idx.values()}
|
||||
applied, skipped, rejected, warned = 0, 0, [], []
|
||||
for it in items:
|
||||
if "msgid" in it:
|
||||
key = (it.get("msgctxt"), it["msgid"])
|
||||
i = idx.get(key)
|
||||
label = (f"[{key[0]}] " if key[0] else "") + key[1][:70].replace("\n", "\\n")
|
||||
else:
|
||||
i = by_id.get(it.get("id"))
|
||||
label = f"id {it.get('id')}" if i is None else c.entries[i].msgid[:70].replace("\n", "\\n")
|
||||
if i is None:
|
||||
rejected.append((label, ["no such entry in the catalog (give its id, or msgid and msgctxt)"]))
|
||||
continue
|
||||
e = c.entries[i]
|
||||
if e.msgid_plural is not None and "msgstr_plural" not in it:
|
||||
rejected.append((label, [f"plural entry: give msgstr_plural with {c.nplurals} forms"]))
|
||||
continue
|
||||
strs = it["msgstr_plural"] if e.msgid_plural is not None else [it.get("msgstr", "")]
|
||||
if not strs or all(not s for s in strs):
|
||||
skipped += 1
|
||||
continue
|
||||
if not a.overwrite and not needs_translation(e, c.nplurals, include_fuzzy=True):
|
||||
rejected.append((label, ["already translated (pass --overwrite to replace)"]))
|
||||
continue
|
||||
errors, warnings = validate(e, strs, c.nplurals, g, a.lang)
|
||||
if errors:
|
||||
rejected.append((label, errors))
|
||||
continue
|
||||
if warnings:
|
||||
warned.append((label, warnings))
|
||||
c.changes[i] = e.rewrite(strs, ai=not a.human, review=it.get("review"))
|
||||
applied += 1
|
||||
if not a.dry_run and c.changes:
|
||||
c.save()
|
||||
for label, msgs in rejected:
|
||||
print(f"REJECTED {label}\n " + "\n ".join(msgs))
|
||||
for label, msgs in warned:
|
||||
print(f"WARNING {label}\n " + "\n ".join(msgs))
|
||||
print(f"{'would apply' if a.dry_run else 'applied'} {applied}, rejected {len(rejected)}, warnings {len(warned)}, blank skipped {skipped}")
|
||||
return 1 if rejected else 0
|
||||
|
||||
|
||||
def find_msgfmt():
|
||||
exe = REPO / "tools" / "msgfmt.exe"
|
||||
if os.name == "nt" and exe.exists():
|
||||
return str(exe)
|
||||
from shutil import which
|
||||
return which("msgfmt")
|
||||
|
||||
|
||||
def cmd_check(a):
|
||||
g = None if a.no_glossary else Glossary(a.wiki, quiet=True)
|
||||
msgfmt = find_msgfmt()
|
||||
status = 0
|
||||
for lang in a.lang or all_langs():
|
||||
c = Catalog(catalog_path(lang))
|
||||
errs = warns = 0
|
||||
for e in c.active():
|
||||
if a.scope == "ai" and not e.ai:
|
||||
continue
|
||||
strs = e.msgstrs()
|
||||
if all(s == "" for s in strs) or e.fuzzy:
|
||||
continue
|
||||
errors, warnings = validate(e, strs, c.nplurals, g, lang)
|
||||
if errors or (warnings and a.warnings):
|
||||
label = (f"[{e.msgctxt}] " if e.msgctxt else "") + e.msgid[:70].replace("\n", "\\n")
|
||||
print(f"{lang} line {e.first_line + 1}: {label}")
|
||||
for m in errors:
|
||||
print(f" ERROR {m}")
|
||||
for m in warnings if a.warnings else []:
|
||||
print(f" warn {m}")
|
||||
errs += bool(errors)
|
||||
warns += bool(warnings)
|
||||
if msgfmt:
|
||||
fd, mo = tempfile.mkstemp(suffix=".mo") # Windows msgfmt cannot write to "nul"
|
||||
os.close(fd)
|
||||
r = subprocess.run([msgfmt, "--check-format", "-o", mo, str(c.path)], capture_output=True, text=True)
|
||||
os.unlink(mo)
|
||||
if r.returncode:
|
||||
print(f"{lang}: msgfmt --check-format failed\n{r.stderr.strip()}")
|
||||
status = 1
|
||||
print(f"{lang}: {errs} entries with errors, {warns} with warnings (scope: {a.scope})")
|
||||
status |= bool(errs)
|
||||
if not msgfmt:
|
||||
print("note: msgfmt not found; skipped --check-format", file=sys.stderr)
|
||||
return status
|
||||
|
||||
|
||||
def cmd_lookup(a):
|
||||
c = Catalog(catalog_path(a.lang))
|
||||
rx = re.compile(a.pattern, re.I)
|
||||
n = 0
|
||||
for e in c.entries:
|
||||
strs = [s for s in e.msgstrs() if s]
|
||||
if e.is_header or not strs:
|
||||
continue
|
||||
texts = strs if a.msgstr else [e.msgid, e.msgid_plural or ""]
|
||||
if not any(rx.search(t) for t in texts):
|
||||
continue
|
||||
mark = "obsolete " if e.obsolete else f"{e.id()} " + ("AI " if e.ai else "")
|
||||
ctx = f"[{e.msgctxt}] " if e.msgctxt else ""
|
||||
print(f"{mark}{ctx}{json.dumps(e.msgid, ensure_ascii=False)}\n -> {json.dumps(strs[0] if len(strs) == 1 else strs, ensure_ascii=False)}")
|
||||
n += 1
|
||||
if n >= a.limit:
|
||||
print("... (limit reached)")
|
||||
break
|
||||
|
||||
|
||||
def cmd_glossary(a):
|
||||
g = Glossary(a.wiki)
|
||||
col = g.column(a.lang)
|
||||
if col is None:
|
||||
print(f"'{a.lang}' has no glossary column yet; add one with glossary-set --set {a.lang}=...")
|
||||
rx = re.compile(a.term, re.I) if a.term else None
|
||||
for r in g.rows:
|
||||
if rx and not rx.search(r[0]):
|
||||
continue
|
||||
val = r[col] if col is not None and r[col] else "—"
|
||||
print(f"{r[0]} => {val}\n {r[1]}")
|
||||
notes = g.language_notes(a.lang)
|
||||
if notes and not a.term:
|
||||
print("\n" + notes)
|
||||
|
||||
|
||||
STOP = set("""a an and are as at be been but by can could do does for from has have how if in into is it its
|
||||
may more most must no not of on once one only or other out over same set should so some such than that the
|
||||
their them then there these this those to too two up use used uses using very was when where whether which
|
||||
while will with without would you your yet all any each every per both also between before after first last
|
||||
off new now get gets let lets just already instead still even back down here make makes made via""".split())
|
||||
|
||||
|
||||
def _singular(key):
|
||||
return " ".join(re.sub(r"(?<=[a-z]{3})(es|s)$", "", w) for w in key.split())
|
||||
|
||||
|
||||
def kept_in_english(g):
|
||||
"""Names from the glossary page's "Kept in English" table."""
|
||||
text = g.md.read_text(encoding="utf-8-sig")
|
||||
m = re.search(r"^## Kept in English.*?$(.*?)(?=^## )", text, re.M | re.S)
|
||||
names = set()
|
||||
for row in re.findall(r"^\| (.*?) \|", m.group(1) if m else "", re.M):
|
||||
for piece in re.split(r"[,/:]|\bplus\b", row.replace("**", "").replace("`", "")):
|
||||
if piece.strip():
|
||||
names.add(_norm(piece.strip()))
|
||||
return names
|
||||
|
||||
|
||||
def cmd_candidates(a):
|
||||
g = Glossary(a.wiki)
|
||||
known = kept_in_english(g)
|
||||
for row, _ in g.matchers:
|
||||
known |= {_norm(x.strip()) for x in base_term(row[0]).split(" / ")}
|
||||
known |= {_singular(k) for k in known}
|
||||
known |= {w for k in known if " " in k for w in k.split()} # "tower" of "prime tower"
|
||||
pending = {}
|
||||
labels = set()
|
||||
for lang in all_langs():
|
||||
c = Catalog(catalog_path(lang))
|
||||
for e in c.active():
|
||||
labels.add(_norm(e.msgid))
|
||||
if needs_translation(e, c.nplurals):
|
||||
pending.setdefault(e.key(), set()).add(lang)
|
||||
counts = {} # phrase -> [strings, max langs, display, example, capitalised mid-sentence]
|
||||
for (ctx, msgid), langs in pending.items():
|
||||
seen = set()
|
||||
for chunk in re.split(r"[.,;:!?()\[\]\"\n—–]+|\s-\s", msgid):
|
||||
words = [re.sub(r"'s$", "", w) for w in re.findall(r"[A-Za-z][A-Za-z0-9-]*(?:'s)?", chunk)]
|
||||
# Capitals only mean a name inside an ordinary sentence, not in a Title Case label.
|
||||
sentence = len(words) >= 4 and sum(w[0].isupper() for w in words) * 2 < len(words)
|
||||
for n in (1, 2, 3):
|
||||
for i in range(len(words) - n + 1):
|
||||
gram = words[i:i + n]
|
||||
if gram[0].lower() in STOP or gram[-1].lower() in STOP or len("".join(gram)) < 4 \
|
||||
or any(w.lower() in STOP and w.lower() != "of" for w in gram):
|
||||
continue
|
||||
key = _norm(" ".join(gram))
|
||||
if key in seen or key in known or _singular(key) in known:
|
||||
continue
|
||||
seen.add(key)
|
||||
d = counts.setdefault(key, [0, 0, " ".join(gram), msgid, False])
|
||||
d[0] += 1
|
||||
d[1] = max(d[1], len(langs))
|
||||
d[4] |= sentence and i > 0 and all(w[0].isupper() for w in gram)
|
||||
# A term is a phrase, or a word capitalised mid-sentence or written as an acronym.
|
||||
keep = {k: v for k, v in counts.items()
|
||||
if v[0] >= a.min_count and (" " in k or v[4] or v[2].isupper())}
|
||||
# Drop fragments only ever seen inside a longer candidate ("IQEX parallel" in "IDEX IQEX parallel").
|
||||
keep = {k: v for k, v in keep.items()
|
||||
if not any(k != k2 and re.search(r"(^| )" + re.escape(k) + r"( |$)", k2) and v2[0] >= v[0] for k2, v2 in keep.items())}
|
||||
rows = sorted(keep.items(), key=lambda kv: (-kv[1][0], -len(kv[0].split())))
|
||||
print("strings langs phrase [label = also a msgid of its own] e.g.")
|
||||
for k, (cnt, langs, text, example, _) in rows[:a.limit]:
|
||||
ex = example.replace("\n", " ")
|
||||
print(f"{cnt:7} {langs:6} {text}{' [label]' if k in labels else ''} e.g. {ex[:70]}{'…' if len(ex) > 70 else ''}")
|
||||
|
||||
|
||||
def cmd_glossary_set(a):
|
||||
wiki = find_wiki(a.wiki)
|
||||
if not wiki:
|
||||
print("No OrcaSlicer_WIKI clone found (looked at --wiki, $ORCA_WIKI_DIR and next to this repository).\n"
|
||||
"The glossary must be updated with these terms before the translations that use them ship:\n"
|
||||
f" {a.term}: " + ", ".join(a.set) + "\n"
|
||||
"Clone https://github.com/OrcaSlicer/OrcaSlicer_WIKI next to this repository, or pass --wiki.", file=sys.stderr)
|
||||
return 2
|
||||
tsv = wiki / GLOSSARY_TSV
|
||||
lock = tsv.with_suffix(".lock")
|
||||
for _ in range(100):
|
||||
try:
|
||||
fd = os.open(lock, os.O_CREAT | os.O_EXCL)
|
||||
break
|
||||
except FileExistsError:
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
sys.exit(f"could not lock {lock}; remove it if no other run is active")
|
||||
try:
|
||||
data = tsv.read_bytes()
|
||||
bom = data.startswith(b"\xef\xbb\xbf")
|
||||
text = data.decode("utf-8-sig")
|
||||
nl = "\r\n" if "\r\n" in text else "\n"
|
||||
lines = text.splitlines()
|
||||
header = lines[0].split("\t")
|
||||
values = {}
|
||||
for s in a.set:
|
||||
lang, _, val = s.partition("=")
|
||||
if lang not in header:
|
||||
sys.exit(f"no glossary column '{lang}'")
|
||||
if "\t" in val or "\n" in val:
|
||||
sys.exit("values cannot contain tabs or line breaks")
|
||||
values[header.index(lang)] = val.strip()
|
||||
row_i = next((i for i, l in enumerate(lines[1:], 1) if l.split("\t")[0] == a.term), None)
|
||||
new = row_i is None
|
||||
if new:
|
||||
if not a.description:
|
||||
sys.exit("a new term needs --description (one sentence saying what it is)")
|
||||
row = [a.term, a.description] + [""] * (len(header) - 2)
|
||||
lines.append("")
|
||||
row_i = len(lines) - 1
|
||||
else:
|
||||
row = lines[row_i].split("\t")
|
||||
row += [""] * (len(header) - len(row))
|
||||
if a.description:
|
||||
row[1] = a.description
|
||||
conflicts = [f"{header[i]}: '{row[i]}' -> '{v}'" for i, v in values.items() if row[i].strip() not in MISSING and row[i] != v]
|
||||
if conflicts and not a.replace:
|
||||
sys.exit("established translations differ (pass --replace, and update the catalogs to match):\n " + "\n ".join(conflicts))
|
||||
for i, v in values.items():
|
||||
row[i] = v
|
||||
lines[row_i] = "\t".join(row)
|
||||
tsv.write_bytes((b"\xef\xbb\xbf" if bom else b"") + (nl.join(lines) + nl).encode("utf-8"))
|
||||
finally:
|
||||
os.close(fd)
|
||||
os.unlink(lock)
|
||||
print(f"glossary: {'added' if new else 'updated'} '{a.term}'")
|
||||
gen = wiki / "generate_glossary.py"
|
||||
if gen.exists():
|
||||
r = subprocess.run([sys.executable, str(gen), "--update"], cwd=wiki, capture_output=True, text=True)
|
||||
print((r.stdout + r.stderr).strip())
|
||||
return r.returncode
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
p.add_argument("--wiki", help="path to an OrcaSlicer_WIKI clone")
|
||||
p.add_argument("--i18n", help="catalog root to use instead of localization/i18n")
|
||||
sub = p.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
s = sub.add_parser("status")
|
||||
s.add_argument("--lang", action="append")
|
||||
s.set_defaults(func=cmd_status)
|
||||
|
||||
s = sub.add_parser("pending")
|
||||
s.add_argument("--lang", required=True)
|
||||
s.add_argument("--offset", type=int, default=0)
|
||||
s.add_argument("--limit", type=int, default=60)
|
||||
s.add_argument("--out")
|
||||
s.add_argument("--include-fuzzy", action=argparse.BooleanOptionalAction, default=True,
|
||||
help="list fuzzy entries too (default): users never see them")
|
||||
s.set_defaults(func=cmd_pending)
|
||||
|
||||
s = sub.add_parser("apply")
|
||||
s.add_argument("--lang", required=True)
|
||||
s.add_argument("--input", required=True)
|
||||
s.add_argument("--overwrite", action="store_true", help="also replace existing translations")
|
||||
s.add_argument("--human", action="store_true", help="do not add '# AI Translated' (a person wrote these)")
|
||||
s.add_argument("--dry-run", action="store_true")
|
||||
s.add_argument("--no-glossary", action="store_true")
|
||||
s.set_defaults(func=cmd_apply)
|
||||
|
||||
s = sub.add_parser("check")
|
||||
s.add_argument("--lang", action="append")
|
||||
s.add_argument("--scope", choices=["ai", "all"], default="ai")
|
||||
s.add_argument("--warnings", action="store_true", help="also print warnings")
|
||||
s.add_argument("--no-glossary", action="store_true")
|
||||
s.set_defaults(func=cmd_check)
|
||||
|
||||
s = sub.add_parser("lookup")
|
||||
s.add_argument("--lang", required=True)
|
||||
s.add_argument("pattern")
|
||||
s.add_argument("--msgstr", action="store_true", help="search the translations instead of the English")
|
||||
s.add_argument("--limit", type=int, default=40)
|
||||
s.set_defaults(func=cmd_lookup)
|
||||
|
||||
s = sub.add_parser("glossary")
|
||||
s.add_argument("--lang", required=True)
|
||||
s.add_argument("term", nargs="?")
|
||||
s.set_defaults(func=cmd_glossary)
|
||||
|
||||
s = sub.add_parser("candidates")
|
||||
s.add_argument("--min-count", type=int, default=3)
|
||||
s.add_argument("--limit", type=int, default=80)
|
||||
s.set_defaults(func=cmd_candidates)
|
||||
|
||||
s = sub.add_parser("glossary-set")
|
||||
s.add_argument("--term", required=True)
|
||||
s.add_argument("--description")
|
||||
s.add_argument("--set", action="append", default=[], metavar="LANG=VALUE")
|
||||
s.add_argument("--replace", action="store_true")
|
||||
s.set_defaults(func=cmd_glossary_set)
|
||||
|
||||
a = p.parse_args()
|
||||
if a.i18n:
|
||||
global I18N
|
||||
I18N = Path(a.i18n)
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
sys.exit(a.func(a) or 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -570,6 +570,11 @@ Details [source] (`Widgets/PopupWindow.cpp`).
|
||||
- On GTK the sub binds an idle handler. While both are shown and the cursor is over main but not over the
|
||||
sub, it builds a `wxMouseEvent(wxEVT_MOTION)` from `wxGetMousePosition()`, calls `mainDropDown->mouseMove(ev)`
|
||||
**directly** (nothing is posted), and calls `e.RequestMore()` to keep polling.
|
||||
- On GTK the sub also receives the wheel events the user raises over main: GDK sends a `wl_pointer.axis` only
|
||||
to the surface the pointer is over, and GTK then hands that `GDK_SCROLL` to the chain's grab widget, which is
|
||||
the sub. The sub installs a `GtkWidget::event` handler that replays the event on main with
|
||||
`gtk_propagate_event(main->GetConnectWidget(), event)` when the event's GDK window belongs to main
|
||||
(`DropDown::messureSize`).
|
||||
- **GTK wrapper sizing.** `messureSize` calls `gtk_window_resize` on `m_widget` after `SetSize`, because wxGTK's
|
||||
`DoSetSize` only uses `gtk_widget_set_size_request` ("gtk_window_resize does not work for GTK_WINDOW_POPUP",
|
||||
`src/gtk/popupwin.cpp:181-188`).
|
||||
@@ -607,6 +612,32 @@ Details [source] (`Widgets/PopupWindow.cpp`).
|
||||
```
|
||||
Cite: c0ae2bda99, b9ff15054f (`DropDown::mouseMove`, `DropDown::messureSize`, `DropDown::ShouldDismissOnTopWindowDeactivate`,
|
||||
`PopupWindow::ShouldDismissOnTopWindowDeactivate`).
|
||||
- **Rule:** On GTK, route a chained popup's wheel event by the GDK window it names, not by the grab widget and not
|
||||
by the global cursor position.
|
||||
**Why:** While the sub holds the grab, `gtk_main_do_event` hands every `GDK_SCROLL` of the chain to the grab
|
||||
widget (the sub) with its original, un-rebased coordinates [source] (`gtkmain.c:1789-1792`, 1923-1924), while
|
||||
GDK Wayland sends the axis to the surface under the pointer only (`pointer_handle_axis` → `create_scroll_event`,
|
||||
`gdkdevice-wayland.c:1929, 1527`). The sub therefore sees and consumes wheel events raised over main, so the
|
||||
main list never scrolls, on X11 and Wayland alike. A hit test against `wxGetMousePosition()` cannot replace the
|
||||
window test: global coordinates are unreliable on Wayland (`mouse-keyboard-focus.md`). `DropDown` connects a
|
||||
`GtkWidget::event` handler on the sub's `GtkWindow` (its `m_widget`), which is emitted before wx's
|
||||
`::scroll-event` handler on the same widget and suppresses it when it returns TRUE (`gtkwidget.c:7696`), then
|
||||
delivers the event with `gtk_propagate_event(main->GetConnectWidget(), event)`. Returning TRUE there also stops
|
||||
the parent-chain propagation.
|
||||
```cpp
|
||||
// Wrong: emitted on the popup's outer GtkWindow, where wx has no handlers at all
|
||||
g_signal_emit_by_name(main->m_widget, "scroll-event", event, &handled);
|
||||
// Right (wxGTK): replay GTK's own delivery on the widget wx listens to
|
||||
gtk_propagate_event(main->GetConnectWidget(), event);
|
||||
```
|
||||
**Where wx listens [source].** `wxPopupWindow::Create` builds a popup from two widgets: `m_widget` is the outer
|
||||
`GtkWindow` and `m_wxwindow` is a `wxPizza` child added to it. `wxWindowGTK::GetConnectWidget()` is
|
||||
`m_wxwindow ? m_wxwindow : m_widget`, and `ConnectWidget()` — which binds `button_press_event`, `motion_notify_event`
|
||||
and `scroll_event` — is called on that widget (`src/gtk/window.cpp` `Create`, `GetConnectWidget`). A signal emitted
|
||||
on the outer `GtkWindow` therefore reaches no wx handler; only events GTK delivers to the inner widget, or to a
|
||||
descendant of the grab widget, are seen by wx. `GTKGetConnectWindow()`/`GTKGetMainWindow()` are the matching
|
||||
GdkWindows.
|
||||
Cite: `DropDown::messureSize`, `DropDown::mouseWheelMoved`.
|
||||
- **Rule:** When shrinking a dropdown to fit above the display bottom, give up if fewer than two rows would
|
||||
remain.
|
||||
**Why:** On Wayland the popup can land where almost no vertical space is left. Clamping to that sliver made an
|
||||
|
||||
@@ -13,6 +13,7 @@ on:
|
||||
# both it and its tests live in scripts/, so a PR touching only those must still run
|
||||
# this workflow.
|
||||
- 'resources/printers/**'
|
||||
- 'resources/info/legacy_compatible_printers.json'
|
||||
- 'scripts/**'
|
||||
# orca_profile_tool.py reads the variant key sets from PrintConfig.cpp, and its
|
||||
# tests the obsolete keys, so a PR changing either must be checked against the profiles.
|
||||
@@ -59,6 +60,21 @@ jobs:
|
||||
python3 ./scripts/orca_profile_tool.py check 2>&1 | tee ${{ runner.temp }}/profile_tool.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
|
||||
# The app migrates user filament presets made against 2.4.2 back to the printers their
|
||||
# parent listed then, from resources/info/legacy_compatible_printers.json. A PR that
|
||||
# renames a filament preset or narrows its compatible_printers changes what that map
|
||||
# must say, so it has to regenerate it.
|
||||
- name: Check the legacy compatible printers map
|
||||
id: legacy_compat
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set -o pipefail
|
||||
base="${{ runner.temp }}/v2.4.2"
|
||||
git fetch --no-tags --depth=1 origin refs/tags/v2.4.2:refs/tags/v2.4.2
|
||||
mkdir -p "$base"
|
||||
git archive v2.4.2 resources/profiles | tar -x -C "$base"
|
||||
python3 ./scripts/orca_profile_tool.py legacy-compat --base "$base/resources/profiles" --check 2>&1 | tee ${{ runner.temp }}/legacy_compat.log
|
||||
|
||||
# download
|
||||
- name: Download
|
||||
working-directory: ${{ github.workspace }}
|
||||
@@ -217,7 +233,7 @@ jobs:
|
||||
echo "${{ github.event.pull_request.number }}" > ${{ runner.temp }}/profile-check-results/pr_number.txt
|
||||
|
||||
- name: Prepare comment artifact
|
||||
if: ${{ always() && github.event_name == 'pull_request' && (steps.profile_tool.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
if: ${{ always() && github.event_name == 'pull_request' && (steps.profile_tool.outcome == 'failure' || steps.legacy_compat.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
run: |
|
||||
{
|
||||
# Marker matched by check_profiles_comment.yml to delete prior comments.
|
||||
@@ -234,6 +250,17 @@ jobs:
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.legacy_compat.outcome }}" = "failure" ]; then
|
||||
echo "### Legacy Compatible Printers Map Out of Date"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/legacy_compat.log || echo "No output captured"
|
||||
echo '```'
|
||||
echo ""
|
||||
echo 'Regenerate it: `git archive v2.4.2 resources/profiles | tar -x -C /tmp/v2.4.2`, then `python3 scripts/orca_profile_tool.py legacy-compat --base /tmp/v2.4.2/resources/profiles`.'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_system.outcome }}" = "failure" ]; then
|
||||
echo "### System Profile Validation Failed"
|
||||
echo ""
|
||||
@@ -283,7 +310,7 @@ jobs:
|
||||
retention-days: 1
|
||||
|
||||
- name: Fail if any check failed
|
||||
if: ${{ always() && (steps.profile_tool.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
if: ${{ always() && (steps.profile_tool.outcome == 'failure' || steps.legacy_compat.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
run: |
|
||||
echo "One or more profile checks failed; see the step logs above."
|
||||
echo 'Reproduce the whole run locally with scripts/check_profile.sh (scripts\check_profile.bat on Windows).'
|
||||
|
||||
@@ -67,6 +67,7 @@ ctest --test-dir ./tests/fff_print -C Release
|
||||
- Keep code concise and clear. Manually simplify AI generated bloated codes before review.
|
||||
- Include targeted tests or documented verification for behavior changes, especially in slicing logic, profiles, formats, and GUI defaults.
|
||||
- For profile changes (`resources/profiles/<Vendor>/**`), check that `version` in the sibling `resources/profiles/<Vendor>.json` was bumped.
|
||||
- For new or changed UI strings, check they follow [Writing translatable strings in the source](#writing-translatable-strings-in-the-source): no concatenated fragments, plural forms for counts, contexts for ambiguous words.
|
||||
- For translation changes (`localization/i18n/**/*.po`), check that recurring terms match the [Localization glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/developer_reference/localization_glossary.md) for that language.
|
||||
|
||||
## Localization & translations
|
||||
@@ -74,6 +75,19 @@ ctest --test-dir ./tests/fff_print -C Release
|
||||
Catalogs live in `localization/i18n/<lang>/OrcaSlicer_<lang>.po`; the template is `OrcaSlicer.pot`.
|
||||
See the [Localization guide](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/developer_reference/localization_guide.md) for the human-facing version of these principles.
|
||||
|
||||
### Writing translatable strings in the source
|
||||
|
||||
Translators see one msgid at a time and cannot change the code around it, so each message must be complete in a single msgid. Use the wrapper that fits instead of assembling text from pieces:
|
||||
|
||||
- **One msgid per sentence, with placeholders.** Never build a message by concatenating translated fragments (`_L("A") + name + _L(" is B")`) or by splicing a translated word such as `_L("left")` into another sentence: the translator can't reorder or inflect the parts. Write `format(_L("%1% is too close to others"), name)`.
|
||||
- **A count needs a plural form.** Don't write `file(s)` or leave a verb unchanged after a number. Use `_L_PLURAL("%1% object", "%1% objects", n)`. libslic3r has no plural lookup, so word the message so it doesn't depend on a count, or build it in the GUI.
|
||||
- **An ambiguous word needs a context.** When a short string means different things in different places (verb or noun, a mode name, a CAD term), give each sense its own context with `_L_CONTEXT`/`_u8L_CONTEXT`/`L_CONTEXT`. Keep the most common sense without a context so its existing translations stay valid.
|
||||
- **Mark every user-visible string** (`_L`/`_u8L`, or `L` where it is translated later) and list new source files in `localization/i18n/list.txt`: files that aren't listed are never extracted.
|
||||
- Add a `// TRN` comment above a new string whose meaning or placeholders aren't obvious.
|
||||
- Never choose behavior by comparing translated text; compare ids or flags.
|
||||
|
||||
See `.claude/skills/orca-translations/references/source-audit.md` for the full checklist.
|
||||
|
||||
### Terminology
|
||||
|
||||
- Use the [Localization glossary](https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/developer_reference/localization_glossary.md) as the source of truth for recurring terms, so the same English term is always rendered the same way within a language, and terms that must stay in English (brand/product names, acronyms, materials, file formats, G-code tokens, macros/variables/identifiers) are not translated.
|
||||
|
||||
+22
-3
@@ -8,7 +8,7 @@ SCRIPT_PATH=$(dirname "$(readlink -f "${0}")")
|
||||
pushd "${SCRIPT_PATH}" > /dev/null
|
||||
|
||||
function usage() {
|
||||
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-J N][-p][-r][-s][-t][-u][-l][-L]"
|
||||
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-J N][-p][-r][-s][-t][-u][-l][-L] [-- CMAKE_ARGS...]"
|
||||
echo " -1: limit builds to one core (where possible)"
|
||||
echo " -j N: limit builds to N cores (where possible)"
|
||||
echo " -J N: build up to N dependencies at a time, each still using -j jobs (default: 1)"
|
||||
@@ -29,11 +29,15 @@ function usage() {
|
||||
echo " -u: install system dependencies (asks for sudo password; build prerequisite)"
|
||||
echo " -l: use Clang instead of GCC (default: GCC)"
|
||||
echo " -L: use ld.lld as linker (if available)"
|
||||
echo " -- CMAKE_ARGS...: pass everything after '--' to the cmake configure step of the deps (-d) and OrcaSlicer (-s/-t) builds,"
|
||||
echo " e.g. -DCMAKE_CXX_FLAGS=\"-O2 -march=native\", -DCMAKE_CXX_COMPILER=g++-14, -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=mold."
|
||||
echo " They come last on the cmake command line, so they override what -l and -L set."
|
||||
echo "For a first use, you want to './${SCRIPT_NAME} -u'"
|
||||
echo " and then './${SCRIPT_NAME} -dsi'"
|
||||
echo "For a GitHub Actions-like Linux build locally, use './${SCRIPT_NAME} -g -istrlL'"
|
||||
echo "Use './${SCRIPT_NAME} -gF -istrlL' to rebuild the cached runner image first."
|
||||
echo "Set ORCA_CONTAINER_CLI, ORCA_DOCKER_IMAGE, ORCA_DOCKER_BASE_IMAGE, or ORCA_DOCKER_CMAKE_VERSION to override the container runtime, cached image tag, base image, or CMake version."
|
||||
echo "DEPS_EXTRA_BUILD_ARGS and ORCA_EXTRA_BUILD_ARGS add whitespace-separated cmake configure arguments to the deps and OrcaSlicer builds; prefer '--' for arguments that contain spaces."
|
||||
}
|
||||
|
||||
SLIC3R_PRECOMPILED_HEADERS="ON"
|
||||
@@ -131,6 +135,20 @@ while getopts ":1j:J:bcCdDeFghiprstulL" opt ; do
|
||||
esac
|
||||
done
|
||||
|
||||
# getopts stops at '--'; whatever follows is handed to cmake unchanged.
|
||||
if [[ ${OPTIND} -le $# ]] ; then
|
||||
separator_index=$((OPTIND-1))
|
||||
if [[ "${!separator_index}" != "--" ]] ; then
|
||||
echo "Unexpected argument '${!OPTIND}': cmake arguments must follow '--', aborting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
shift $((OPTIND-1))
|
||||
EXTRA_CMAKE_ARGS=("$@")
|
||||
if [[ ${#EXTRA_CMAKE_ARGS[@]} -gt 0 ]] ; then
|
||||
FORWARDED_ARGS+=("--" "${EXTRA_CMAKE_ARGS[@]}")
|
||||
fi
|
||||
|
||||
if [ ${OPTIND} -eq 1 ] ; then
|
||||
usage
|
||||
exit 1
|
||||
@@ -547,7 +565,7 @@ if [[ -n "${BUILD_DEPS}" ]] ; then
|
||||
BUILD_ARGS+=(-DCMAKE_BUILD_TYPE="${BUILD_CONFIG}")
|
||||
fi
|
||||
|
||||
print_and_run cmake -S deps -B deps/$BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G Ninja "${COLORED_OUTPUT}" "${BUILD_ARGS[@]}"
|
||||
print_and_run cmake -S deps -B deps/$BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G Ninja "${COLORED_OUTPUT}" "${BUILD_ARGS[@]}" "${EXTRA_CMAKE_ARGS[@]}"
|
||||
# The top-level build runs one dependency at a time by default, which keeps the console
|
||||
# output readable and lets that dependency's own build use all of CMAKE_BUILD_PARALLEL_LEVEL.
|
||||
# -J raises the top level instead, and -j still applies in full to every dependency, so the
|
||||
@@ -593,7 +611,8 @@ if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
|
||||
-DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} \
|
||||
-DORCA_TOOLS=ON \
|
||||
"${COLORED_OUTPUT}" \
|
||||
"${BUILD_ARGS[@]}"
|
||||
"${BUILD_ARGS[@]}" \
|
||||
"${EXTRA_CMAKE_ARGS[@]}"
|
||||
echo "done"
|
||||
if [[ -n "${BUILD_ORCA}" ]]; then
|
||||
echo "Building OrcaSlicer ..."
|
||||
|
||||
@@ -88,18 +88,6 @@ struct NfpPConfig {
|
||||
*/
|
||||
bool explore_holes = false;
|
||||
|
||||
/**
|
||||
* @brief Keep the final pile on the bin.
|
||||
*
|
||||
* The final alignment centres the pile on the alignment target. A target
|
||||
* near an edge (a belt printer starts its parts at the leading end of the
|
||||
* belt) would push part of a pile that is larger than the room around that
|
||||
* point off the bed; with this set the pile stops at the edge instead, and a
|
||||
* pile that does not fit along an axis is centred on it. Off by default, so
|
||||
* the alignment of every other printer is unchanged.
|
||||
*/
|
||||
bool clamp_to_bin = false;
|
||||
|
||||
/**
|
||||
* @brief If true, use all CPUs available. Run on a single core otherwise.
|
||||
*/
|
||||
@@ -1125,22 +1113,22 @@ private:
|
||||
|
||||
auto d = cb - ci;
|
||||
|
||||
// Keep the pile on the bin (see Config::clamp_to_bin). The items' boxes carry
|
||||
// their inflation, which is the margin left at the edge.
|
||||
if (config_.clamp_to_bin) {
|
||||
auto on_bin = [](Coord lo, Coord hi, Coord bin_lo, Coord bin_hi, Coord shift) {
|
||||
if (hi - lo >= bin_hi - bin_lo)
|
||||
return (bin_lo + bin_hi) / 2 - (lo + hi) / 2;
|
||||
if (lo + shift < bin_lo)
|
||||
shift = bin_lo - lo;
|
||||
if (hi + shift > bin_hi)
|
||||
shift = bin_hi - hi;
|
||||
return shift;
|
||||
};
|
||||
setX(d, on_bin(getX(bb.minCorner()), getX(bb.maxCorner()), getX(bbin.minCorner()), getX(bbin.maxCorner()), getX(d)));
|
||||
setY(d, on_bin(getY(bb.minCorner()), getY(bb.maxCorner()), getY(bbin.minCorner()), getY(bbin.maxCorner()), getY(d)));
|
||||
cb = ci + d;
|
||||
}
|
||||
// Keep the pile on the bin. Centring it on a target near an edge (a belt
|
||||
// printer starts its parts at the leading end of the belt) would push a pile
|
||||
// larger than the room around that point off the bed, so it stops at the
|
||||
// edge instead; a pile that does not fit along an axis is centred on it.
|
||||
// The items' boxes carry their inflation, which is the margin left at the edge.
|
||||
auto on_bin = [](Coord lo, Coord hi, Coord bin_lo, Coord bin_hi, Coord shift) {
|
||||
if (hi - lo >= bin_hi - bin_lo)
|
||||
return (bin_lo + bin_hi) / 2 - (lo + hi) / 2;
|
||||
if (lo + shift < bin_lo)
|
||||
shift = bin_lo - lo;
|
||||
if (hi + shift > bin_hi)
|
||||
shift = bin_hi - hi;
|
||||
return shift;
|
||||
};
|
||||
setX(d, on_bin(getX(bb.minCorner()), getX(bb.maxCorner()), getX(bbin.minCorner()), getX(bbin.maxCorner()), getX(d)));
|
||||
setY(d, on_bin(getY(bb.minCorner()), getY(bb.maxCorner()), getY(bbin.minCorner()), getY(bbin.maxCorner()), getY(d)));
|
||||
|
||||
// BBS make sure the item won't clash with excluded regions
|
||||
// do we have wipe tower after arranging?
|
||||
@@ -1169,9 +1157,7 @@ private:
|
||||
return;
|
||||
}
|
||||
Item objs_convex_hull_item(objs_convex_hull);
|
||||
Vertex objs_convex_hull_ref = objs_convex_hull_item.referenceVertex();
|
||||
Vertex diff = objs_convex_hull_ref - sl::boundingBox(objs_convex_hull).center();
|
||||
Vertex ref_aligned = cb + diff; // reference point when pile center aligned with bed center
|
||||
Vertex ref_aligned = objs_convex_hull_item.referenceVertex() + d;
|
||||
bool ref_aligned_is_ok = std::any_of(nfps.begin(), nfps.end(), [&ref_aligned](auto& nfp) {return sl::isInside(ref_aligned, nfp); });
|
||||
if (!ref_aligned_is_ok) {
|
||||
// ref_aligned is not good, then find a nearest point on nfp boundary
|
||||
|
||||
+38
-22
@@ -82,9 +82,7 @@ there.
|
||||
strong point is placed, no later strong modifier and no weak modifier is
|
||||
processed for that perimeter.
|
||||
- **Weak:** every weak modifier applies. They are applied from the lowest
|
||||
priority to the highest, so the highest one overwrites overlapping zones. A
|
||||
Blocked modifier that fully contains a perimeter is the exception: it is
|
||||
skipped there (see [Full containment](#full-containment)).
|
||||
priority to the highest, so the highest one overwrites overlapping zones.
|
||||
|
||||
A strong modifier without a usable segment, even one whose fragments were all
|
||||
discarded, passes the turn to the next one.
|
||||
@@ -232,20 +230,23 @@ begin and end positions on the source contour.
|
||||
### Full containment
|
||||
|
||||
A modifier that covers the whole perimeter has no boundaries on it. The policy
|
||||
follows seam painting, where painting a whole perimeter green is a meaningful
|
||||
choice and forbidding the seam all round is not:
|
||||
follows seam painting, where a whole perimeter can be painted in either color:
|
||||
|
||||
- **Seam Enforced** types the whole perimeter, like a perimeter painted green all
|
||||
round, with subdivision applied as described under [Weak modifiers](#weak-modifiers).
|
||||
- **Seam Neutral** types the whole perimeter Neutral, like an unmarked perimeter,
|
||||
clearing painting and lower zones.
|
||||
- **Seam Blocked** is skipped for the perimeter, with the full-containment
|
||||
warning. The seam cannot avoid the whole perimeter, so the modifier does not
|
||||
override anything below it: lower zones and painting stay in effect.
|
||||
- **Seam Center, Left and Right** are skipped with the same warning: there is no
|
||||
intersection to place the point on.
|
||||
- **Seam Blocked** types the whole perimeter Blocked, like a perimeter painted
|
||||
red all round, overriding painting and lower zones. The seam cannot avoid such
|
||||
a perimeter: the seam placer compares Blocked candidates with each other like
|
||||
Neutral ones, so the seam is placed as on an unmarked perimeter. If the
|
||||
perimeter stays Blocked after all weak zones, it is reported in the user
|
||||
warning (see [Diagnostics and warnings](#diagnostics-and-warnings)), so the
|
||||
user can check the modifier.
|
||||
- **Seam Center, Left and Right** are skipped with the full-containment warning:
|
||||
there is no intersection to place the point on.
|
||||
|
||||
Enforced and Neutral take part in the usual priority order (see
|
||||
Enforced, Neutral and Blocked take part in the usual priority order (see
|
||||
[Weak modifiers](#weak-modifiers)).
|
||||
|
||||
The perimeter is fully contained when the united intervals cover every source
|
||||
@@ -311,9 +312,9 @@ into every perimeter that has a strong seam.
|
||||
`collect_weak_modifier_segments()` extracts the segments of every weak modifier
|
||||
before the polygon is modified, so all positions refer to the same contour. Each
|
||||
segment becomes a zone with a type and two boundaries, kept in application
|
||||
order, lowest priority first. Full containment of an Enforced or Neutral
|
||||
modifier becomes a whole-perimeter zone at its place in that order: it has no
|
||||
boundaries and takes part in no insertion or helper step below. The boundaries
|
||||
order, lowest priority first. Full containment of a weak modifier becomes a
|
||||
whole-perimeter zone at its place in that order: it has no boundaries and takes
|
||||
part in no insertion or helper step below. The boundaries
|
||||
carry their positions on the source contour; these remain as provenance after
|
||||
insertion and are not indices into the modified polygon.
|
||||
|
||||
@@ -384,9 +385,10 @@ G-code export issues it as one non-critical warning with the ID
|
||||
`SlicingPreciseSeamWarning`. It is a single line, "Precise Seam: <causes>. Seam
|
||||
placement may differ from expected.", because the export warnings dialog shows
|
||||
only the first line of each warning. Repeated warning events replace the
|
||||
notification instead of appending to it. Except for the "had no effect" cause,
|
||||
the causes name the modifier types involved, as the menu names them, in menu
|
||||
order and each type once, for example "(Seam Left, Seam Enforced)".
|
||||
notification instead of appending to it. Except for the "covers an entire
|
||||
perimeter" and "had no effect" causes, the causes name the modifier types
|
||||
involved, as the menu names them, in menu order and each type once, for example
|
||||
"(Seam Left, Seam Enforced)".
|
||||
The causes are:
|
||||
|
||||
- **failed to process some intersections (types):** at least one fragment was
|
||||
@@ -395,8 +397,18 @@ The causes are:
|
||||
a Seam Center, Left or Right modifier had more than one segment on a
|
||||
perimeter (see [Strong modifiers](#strong-modifiers)).
|
||||
- **a perimeter is fully inside a modifier, the modifier was not applied to it
|
||||
(types):** a Seam Center, Left, Right or Blocked modifier was skipped for a
|
||||
(types):** a Seam Center, Left or Right modifier was skipped for a
|
||||
perimeter (see [Full containment](#full-containment)).
|
||||
- **Seam Blocked modifier "<name>" of "<object>" covers an entire perimeter:**
|
||||
a Seam Blocked modifier covered a whole perimeter (see
|
||||
[Full containment](#full-containment)). Only perimeters whose candidates are
|
||||
all Blocked after all weak zones contribute to this warning, and only through
|
||||
the zone in effect there: `apply_weak_modifiers_to_perimeter()` checks the
|
||||
final types and flags the modifier of the highest whole-perimeter zone when it
|
||||
is Blocked. A lower whole zone is overwritten by it and is not reported. Only
|
||||
the first flagged modifier in print and volume order is named, followed by
|
||||
"(N in total)" when there are several. The type name reuses the menu's
|
||||
translation.
|
||||
- **modifier "<name>" of "<object>" had no effect on the seam (it might not reach
|
||||
the centerline of the printed perimeter):** a modifier was evaluated on at
|
||||
least one perimeter and never gave a segment, full containment or a discarded
|
||||
@@ -420,6 +432,8 @@ The log records the following diagnostic markers:
|
||||
- `[PreciseSeamNoEffect]` for every modifier of the "had no effect" cause, with
|
||||
the object and modifier names. Unlike the user warning, the log lists all of
|
||||
them.
|
||||
- `[PreciseSeamFullyBlocked]` for every modifier of the "covers an entire
|
||||
perimeter" cause, listed the same way.
|
||||
|
||||
Failures and recoveries are counted separately. The first 10 of each per
|
||||
`init()` call are logged in detail, in parallel processing order; if a limit is
|
||||
@@ -563,12 +577,14 @@ last modifier would.
|
||||
priorities, weak boundaries that coincide or share an edge, enforced
|
||||
subdivision, whole-perimeter weak zones with painting and priorities, weak
|
||||
zones over painting's oversampled candidates, the warning type masks, usage
|
||||
tracking for the "had no effect" warning, volume sorting of strong and weak
|
||||
groups, restoration of strong points after alignment, raft layer indexing and
|
||||
structured slices. End-to-end tests slice a real object with Precise Seam
|
||||
tracking for the "had no effect" and whole-perimeter Blocked warnings, volume
|
||||
sorting of strong and weak groups, restoration of strong points after
|
||||
alignment, raft layer indexing and structured slices. End-to-end tests slice
|
||||
a real object with Precise Seam
|
||||
volumes and check the outer wall starts in the exported G-code: every strong
|
||||
mode under several seam positions and with a raft, Enforced and Blocked zones,
|
||||
a modifier with a hole, and the user warning.
|
||||
a perimeter blocked all round under every seam position, a modifier with a
|
||||
hole, and the user warning.
|
||||
- [Seam placer tests](../../tests/fff_print/test_seam_placer.cpp) cover
|
||||
enforced-patch selection independent of the contour start, fully painted
|
||||
contours, duplicate removal, and `Print::apply()` synchronization through type
|
||||
|
||||
+2163
-306
File diff suppressed because it is too large
Load Diff
+4188
-739
File diff suppressed because it is too large
Load Diff
+4244
-715
File diff suppressed because it is too large
Load Diff
+4175
-730
File diff suppressed because it is too large
Load Diff
+2153
-306
File diff suppressed because it is too large
Load Diff
+4136
-718
File diff suppressed because it is too large
Load Diff
+4215
-753
File diff suppressed because it is too large
Load Diff
+4146
-715
File diff suppressed because it is too large
Load Diff
+4206
-751
File diff suppressed because it is too large
Load Diff
+4119
-704
File diff suppressed because it is too large
Load Diff
+4117
-736
File diff suppressed because it is too large
Load Diff
+4084
-719
File diff suppressed because it is too large
Load Diff
@@ -72,6 +72,8 @@ src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoUtils.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
|
||||
@@ -110,6 +112,7 @@ src/slic3r/GUI/Jobs/ArrangeJob.cpp
|
||||
src/slic3r/GUI/Jobs/OrientJob.cpp
|
||||
src/slic3r/GUI/Jobs/FillBedJob.cpp
|
||||
src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
|
||||
src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
|
||||
src/slic3r/GUI/Jobs/BindJob.cpp
|
||||
src/slic3r/GUI/Jobs/PrintJob.cpp
|
||||
src/slic3r/GUI/Jobs/SendJob.cpp
|
||||
@@ -138,6 +141,7 @@ src/slic3r/GUI/DeviceErrorDialog.cpp
|
||||
src/slic3r/GUI/ExtraRenderers.cpp
|
||||
src/slic3r/GUI/EditGCodeDialog.cpp
|
||||
src/slic3r/GUI/Field.cpp
|
||||
src/slic3r/GUI/Field.hpp
|
||||
src/slic3r/GUI/GCodeViewer.cpp
|
||||
src/slic3r/GUI/GLCanvas3D.cpp
|
||||
src/slic3r/GUI/Calibration.cpp
|
||||
@@ -165,6 +169,7 @@ src/slic3r/GUI/PrintOptionsDialog.cpp
|
||||
src/slic3r/GUI/SafetyOptionsDialog.cpp
|
||||
src/slic3r/GUI/ParamsPanel.cpp
|
||||
src/slic3r/GUI/IMEXModesCtrl.cpp
|
||||
src/slic3r/GUI/IMEXFilamentPickerPopover.cpp
|
||||
src/slic3r/GUI/PartPlate.cpp
|
||||
src/slic3r/GUI/Plater.cpp
|
||||
src/slic3r/GUI/Preferences.cpp
|
||||
@@ -212,10 +217,14 @@ src/libslic3r/GCode/SeamPlacer.cpp
|
||||
src/libslic3r/ExtrusionEntity.cpp
|
||||
src/libslic3r/Flow.cpp
|
||||
src/libslic3r/Format/AMF.cpp
|
||||
src/libslic3r/Format/3mf.cpp
|
||||
src/libslic3r/Format/bbs_3mf.cpp
|
||||
src/libslic3r/miniz_extension.cpp
|
||||
src/libslic3r/IMEXHelpers.cpp
|
||||
src/libslic3r/Preset.cpp
|
||||
src/libslic3r/Print.cpp
|
||||
src/libslic3r/BeltPurge.cpp
|
||||
src/libslic3r/AppConfig.cpp
|
||||
src/libslic3r/PrintBase.cpp
|
||||
src/libslic3r/PrintConfig.cpp
|
||||
src/libslic3r/Zipper.cpp
|
||||
@@ -253,6 +262,7 @@ src/slic3r/Utils/MKS.cpp
|
||||
src/slic3r/Utils/Moonraker.cpp
|
||||
src/slic3r/Utils/OctoPrint.cpp
|
||||
src/slic3r/Utils/Repetier.cpp
|
||||
src/slic3r/Utils/ESP3D.cpp
|
||||
src/slic3r/GUI/SendMultiMachinePage.cpp
|
||||
src/slic3r/GUI/MultiMachinePage.cpp
|
||||
src/slic3r/GUI/MultiMachineManagerPage.cpp
|
||||
@@ -307,6 +317,8 @@ src/slic3r/GUI/AuxiliaryDataViewModel.cpp
|
||||
src/slic3r/GUI/AuxiliaryDialog.cpp
|
||||
src/slic3r/GUI/BBLStatusBarPrint.cpp
|
||||
src/slic3r/GUI/BBLStatusBarSend.cpp
|
||||
src/slic3r/GUI/BBLStatusBar.cpp
|
||||
src/slic3r/GUI/BeltPurgeTower.cpp
|
||||
src/slic3r/GUI/BaseTransparentDPIFrame.cpp
|
||||
src/slic3r/GUI/CloneDialog.cpp
|
||||
src/slic3r/GUI/ColorDecomposeDialog.cpp
|
||||
@@ -347,11 +359,27 @@ src/slic3r/GUI/WebViewDialog.cpp
|
||||
src/slic3r/GUI/Widgets/AMSItem.cpp
|
||||
src/slic3r/GUI/Widgets/DialogButtons.cpp
|
||||
src/slic3r/Utils/NetworkAgentFactory.cpp
|
||||
src/slic3r/Utils/MoonrakerPrinterAgent.cpp
|
||||
src/slic3r/Utils/BBLNetworkPlugin.cpp
|
||||
src/slic3r/Utils/OrcaCloudServiceAgent.cpp
|
||||
src/slic3r/plugin/PluginAuditManager.cpp
|
||||
src/slic3r/plugin/PluginConfig.cpp
|
||||
src/slic3r/plugin/PluginResolver.cpp
|
||||
src/slic3r/plugin/CloudPluginService.cpp
|
||||
src/slic3r/plugin/PluginFsUtils.cpp
|
||||
src/slic3r/plugin/PluginHooks.cpp
|
||||
src/slic3r/plugin/PluginLoader.cpp
|
||||
src/slic3r/plugin/PluginManager.cpp
|
||||
src/slic3r/plugin/PythonPluginBridge.cpp
|
||||
src/libslic3r/CAD/SketchEngine.cpp
|
||||
src/libslic3r/CAD/GeometryEngine.cpp
|
||||
src/libslic3r/FilamentMixer.cpp
|
||||
src/libslic3r/Config.cpp
|
||||
src/libslic3r/Format/STEP.cpp
|
||||
src/libslic3r/Format/svg.cpp
|
||||
src/libslic3r/Extruder.cpp
|
||||
src/libslic3r/MeshBoolean.cpp
|
||||
src/libslic3r/utils.cpp
|
||||
src/slic3r/GUI/CAD/DesignOffer.hpp
|
||||
src/slic3r/GUI/CAD/DesignSketchTool.cpp
|
||||
src/slic3r/GUI/EncodedFilament.cpp
|
||||
|
||||
+4269
-738
File diff suppressed because it is too large
Load Diff
+4207
-752
File diff suppressed because it is too large
Load Diff
+4218
-748
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+4274
-765
File diff suppressed because it is too large
Load Diff
+4277
-806
File diff suppressed because it is too large
Load Diff
+4134
-759
File diff suppressed because it is too large
Load Diff
+4157
-708
File diff suppressed because it is too large
Load Diff
+4386
-750
File diff suppressed because it is too large
Load Diff
+4119
-745
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,795 @@
|
||||
{
|
||||
"presets": {
|
||||
"Anycubic Generic ABS": [
|
||||
"Anycubic Kobra 3 0.4 nozzle"
|
||||
],
|
||||
"Anycubic Generic TPU": [
|
||||
"Anycubic Kobra 3 0.4 nozzle"
|
||||
],
|
||||
"Bambu ABS @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu ABS @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu ASA @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL X1C": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.8 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.8 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PC @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PETG @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL X1C": [
|
||||
"Bambu Lab P1P 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.4 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL X1C 0.8 nozzle": [
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL X1C 0.8 nozzle": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Basic @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Basic @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Basic @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Dynamic @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Dynamic @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Galaxy @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Galaxy @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Glow @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Glow @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Marble @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Marble @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Matte @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Matte @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Matte @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Metal @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Metal @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Sparkle @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Sparkle @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Tough+ @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Tough+ @BBL X1C": [
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Tough+ @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Translucent @BBL H2D 0.8 nozzle": [
|
||||
"Bambu Lab H2D 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Translucent @BBL H2DP 0.8 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Translucent @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Wood @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Wood @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PPA-CF @BBL X1C": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.8 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 90A @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 90A @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL H2D": [
|
||||
"Bambu Lab H2D 0.4 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.4 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic ABS": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic ASA": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic ASA-CF": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PA": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PA-CF": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PC": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PETG": [
|
||||
"BLOCKS RD50 V2 0.4 nozzle",
|
||||
"BLOCKS RD50 V2 0.6 nozzle",
|
||||
"BLOCKS RD50 V2 0.8 nozzle",
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PLA": [
|
||||
"BLOCKS RD50 V2 0.4 nozzle",
|
||||
"BLOCKS RD50 V2 0.6 nozzle",
|
||||
"BLOCKS RD50 V2 0.8 nozzle",
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PLA-CF": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic PVA": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks Generic TPU": [
|
||||
"BLOCKS RD50 V2 0.4 nozzle",
|
||||
"BLOCKS RD50 V2 0.6 nozzle",
|
||||
"BLOCKS RD50 V2 0.8 nozzle",
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Creality Generic ABS": [
|
||||
"Creality CR-10 SE 0.2 nozzle",
|
||||
"Creality CR-10 SE 0.4 nozzle",
|
||||
"Creality CR-10 SE 0.6 nozzle",
|
||||
"Creality CR-10 SE 0.8 nozzle",
|
||||
"Creality CR-6 SE 0.2 nozzle",
|
||||
"Creality CR-6 SE 0.4 nozzle",
|
||||
"Creality CR-6 SE 0.6 nozzle",
|
||||
"Creality CR-6 SE 0.8 nozzle",
|
||||
"Creality CR-M4 0.4 nozzle",
|
||||
"Creality Ender-3 V2 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic ABS @Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Creality Generic ABS @Hi-all": [
|
||||
"Creality Hi 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic ABS @K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic ABS @K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic ASA @Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Creality Generic ASA @K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic ASA @K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PA-CF @Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Creality Generic PA-CF @K1-all": [
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PA-CF @K2-all": [
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle"
|
||||
],
|
||||
"Creality Generic PC @K1-all": [
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PETG": [
|
||||
"Creality CR-6 SE 0.2 nozzle",
|
||||
"Creality CR-6 SE 0.4 nozzle",
|
||||
"Creality CR-6 SE 0.6 nozzle",
|
||||
"Creality CR-6 SE 0.8 nozzle",
|
||||
"Creality CR-M4 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PETG @Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 0.4 nozzle",
|
||||
"Creality Ender-3 V3 0.6 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.2 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.4 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.8 nozzle"
|
||||
],
|
||||
"Creality Generic PETG @Hi-all": [
|
||||
"Creality Hi 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PETG @K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PETG @K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PLA": [
|
||||
"Creality CR-10 SE 0.2 nozzle",
|
||||
"Creality CR-10 SE 0.4 nozzle",
|
||||
"Creality CR-10 SE 0.6 nozzle",
|
||||
"Creality CR-10 SE 0.8 nozzle",
|
||||
"Creality CR-6 SE 0.2 nozzle",
|
||||
"Creality CR-6 SE 0.4 nozzle",
|
||||
"Creality CR-6 SE 0.6 nozzle",
|
||||
"Creality CR-6 SE 0.8 nozzle",
|
||||
"Creality CR-M4 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PLA @Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 0.4 nozzle",
|
||||
"Creality Ender-3 V3 0.6 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Creality Generic PLA @K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PLA @K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PLA-CF @K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic PLA-CF @K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic TPU": [
|
||||
"Creality CR-10 SE 0.2 nozzle",
|
||||
"Creality CR-10 SE 0.4 nozzle",
|
||||
"Creality CR-10 SE 0.6 nozzle",
|
||||
"Creality CR-10 SE 0.8 nozzle"
|
||||
],
|
||||
"Creality Generic TPU @Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 0.4 nozzle",
|
||||
"Creality Ender-3 V3 0.6 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.2 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.4 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.8 nozzle"
|
||||
],
|
||||
"Creality Generic TPU @K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Creality Generic TPU @K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Cubicon ABS @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon ABS-A100 @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon ABSk @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PA-CF @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PC @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PETG @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PLA @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PLA+ @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PLAi21 @base": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Flashforge Generic ABS @G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Flashforge Generic ASA @G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Flashforge Generic HIPS": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Flashforge Generic PETG @G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Flashforge Generic PETG-CF @G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Flashforge Generic PLA @G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Flashforge Generic PLA-CF @G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Flashforge HS PLA": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"Flashforge PETG-CF": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"Flashforge PLA-CF": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"Flashforge TPU 95A": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"FusRock Generic PAHT-CF": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"FusRock Generic PET-CF": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Generic PETG HF @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 0.4 nozzle",
|
||||
"Bambu Lab X1 0.6 nozzle",
|
||||
"Bambu Lab X1 0.8 nozzle"
|
||||
],
|
||||
"Generic PLA @Hi-all": [
|
||||
"Creality Hi 0.4 nozzle",
|
||||
"Creality Hi 0.6 nozzle"
|
||||
],
|
||||
"HATCHBOX PETG @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"Prusa Generic PA": [
|
||||
"Prusa MINIIS 0.25 nozzle",
|
||||
"Prusa MINIIS 0.4 nozzle",
|
||||
"Prusa MINIIS 0.6 nozzle",
|
||||
"Prusa MINIIS 0.8 nozzle"
|
||||
],
|
||||
"Prusa Generic PA-CF": [
|
||||
"Prusa MINIIS 0.25 nozzle",
|
||||
"Prusa MINIIS 0.4 nozzle",
|
||||
"Prusa MINIIS 0.6 nozzle",
|
||||
"Prusa MINIIS 0.8 nozzle"
|
||||
],
|
||||
"Prusa Generic PLA-CF": [
|
||||
"Prusa MINIIS 0.25 nozzle",
|
||||
"Prusa MINIIS 0.4 nozzle",
|
||||
"Prusa MINIIS 0.6 nozzle",
|
||||
"Prusa MINIIS 0.8 nozzle"
|
||||
],
|
||||
"QIDI PETG Basic @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"QIDI PETG Rapido @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"QIDI PETG Translucent @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"Sovol Zero PETG HS Nozzle": [
|
||||
"Sovol Zero 0.4 nozzle"
|
||||
],
|
||||
"Sovol Zero PLA Basic HS Nozzle": [
|
||||
"Sovol Zero 0.4 nozzle"
|
||||
],
|
||||
"Sovol Zero PLA Silk HS Nozzle": [
|
||||
"Sovol Zero 0.4 nozzle"
|
||||
],
|
||||
"re3D Greengate rPETG": [
|
||||
"re3D GigabotX 2 1.75 nozzle",
|
||||
"re3D GigabotX 2 XLT 1.75 nozzle",
|
||||
"re3D TerabotX 2 1.75 nozzle"
|
||||
],
|
||||
"re3D PC": [
|
||||
"re3D Gigabot 4 0.8 nozzle",
|
||||
"re3D Gigabot 4 XLT 0.8 nozzle",
|
||||
"re3D Terabot 4 0.8 nozzle"
|
||||
],
|
||||
"re3D PETG": [
|
||||
"re3D Gigabot 4 0.8 nozzle",
|
||||
"re3D Gigabot 4 XLT 0.8 nozzle",
|
||||
"re3D Terabot 4 0.8 nozzle"
|
||||
],
|
||||
"re3D PLA": [
|
||||
"re3D Gigabot 4 0.8 nozzle",
|
||||
"re3D Gigabot 4 XLT 0.8 nozzle",
|
||||
"re3D Terabot 4 0.8 nozzle"
|
||||
],
|
||||
"re3D rPP": [
|
||||
"re3D GigabotX 2 1.75 nozzle",
|
||||
"re3D GigabotX 2 XLT 1.75 nozzle",
|
||||
"re3D TerabotX 2 1.75 nozzle"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"name": "Goofoo",
|
||||
"version": "02.04.00.01",
|
||||
"force_update": "0",
|
||||
"description": "Goofoo configurations",
|
||||
"machine_model_list": [
|
||||
{
|
||||
"name": "Goofoo GP1",
|
||||
"sub_path": "machine/Goofoo GP1.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo TurboM",
|
||||
"sub_path": "machine/Goofoo TurboM.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo Velo+",
|
||||
"sub_path": "machine/Goofoo Velo+.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo Velo+ Tool",
|
||||
"sub_path": "machine/Goofoo Velo+ Tool.json"
|
||||
}
|
||||
],
|
||||
"process_list": [
|
||||
{
|
||||
"name": "fdm_process_common",
|
||||
"sub_path": "process/fdm_process_common.json"
|
||||
},
|
||||
{
|
||||
"name": "fdm_process_klipper_common",
|
||||
"sub_path": "process/fdm_process_klipper_common.json"
|
||||
},
|
||||
{
|
||||
"name": "0.20mm Standard @Goofoo GP1",
|
||||
"sub_path": "process/0.20mm Standard @Goofoo GP1.json"
|
||||
},
|
||||
{
|
||||
"name": "0.20mm Standard @Goofoo TurboM",
|
||||
"sub_path": "process/0.20mm Standard @Goofoo TurboM.json"
|
||||
},
|
||||
{
|
||||
"name": "0.20mm Standard @Goofoo Velo+",
|
||||
"sub_path": "process/0.20mm Standard @Goofoo Velo+.json"
|
||||
},
|
||||
{
|
||||
"name": "0.30mm Standard @Goofoo Velo+",
|
||||
"sub_path": "process/0.30mm Standard @Goofoo Velo+.json"
|
||||
},
|
||||
{
|
||||
"name": "0.10mm Standard @Goofoo Velo+",
|
||||
"sub_path": "process/0.10mm Standard @Goofoo Velo+.json"
|
||||
}
|
||||
],
|
||||
"filament_list": [],
|
||||
"machine_list": [
|
||||
{
|
||||
"name": "fdm_machine_common",
|
||||
"sub_path": "machine/fdm_machine_common.json"
|
||||
},
|
||||
{
|
||||
"name": "fdm_klipper_common",
|
||||
"sub_path": "machine/fdm_klipper_common.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo GP1 0.4 nozzle",
|
||||
"sub_path": "machine/Goofoo GP1 0.4 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo TurboM 0.4 nozzle",
|
||||
"sub_path": "machine/Goofoo TurboM 0.4 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo Velo+ 0.2 nozzle",
|
||||
"sub_path": "machine/Goofoo Velo+ 0.2 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo Velo+ 0.4 nozzle",
|
||||
"sub_path": "machine/Goofoo Velo+ 0.4 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo Velo+ 0.6 nozzle",
|
||||
"sub_path": "machine/Goofoo Velo+ 0.6 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo Velo+ Tool 0.4",
|
||||
"sub_path": "machine/Goofoo Velo+ Tool 0.4.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
|
||||
<g id="Layer_1">
|
||||
<title>Layer 1</title>
|
||||
<text fill="#0000ff" x="31.38885" y="400.22266" id="svg_1" font-size="24" font-family="Noto Sans JP" text-anchor="start" xml:space="preserve" stroke="#0000ff" transform="matrix(2.19884 0 0 1.66297 -63.896 -416.238)">GP1</text>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 373 B |
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
<svg width="600" height="480" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<text transform="matrix(2.3401 0 0 1.462 -92.4668 -168.496)" stroke="#000" stroke-width="3" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="24" id="svg_1" y="421.25588" x="52.33404" fill="#000000">TurboM</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 353 B |
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="480" viewBox="0 0 600 480">
|
||||
<g id="Layer_1">
|
||||
<title>Layer 1</title>
|
||||
<text transform="matrix(2.19884 0 0 1.66297 -203.896 -238.238)" stroke="#0000ff" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="24" id="svg_1" y="400.22266" x="120.07198" fill="#0000ff">VELO+</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 376 B |
Binary file not shown.
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "Goofoo GP1 0.4 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "x4GJ08PooNDQ8WJj",
|
||||
"instantiation": "true",
|
||||
"nozzle_diameter": [
|
||||
"0.4"
|
||||
],
|
||||
"default_filament_profile": [
|
||||
"Goofoo ABS @System"
|
||||
],
|
||||
"printer_model": "Goofoo GP1",
|
||||
"default_print_profile": "0.20mm Standard @Goofoo GP1",
|
||||
"printer_variant": "0.4",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\n;G92 E0",
|
||||
"change_filament_gcode": "G5",
|
||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\n;layer\n;{if layer_num == 2}\n;M106 P1 S255\n;{endif}\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n",
|
||||
"machine_end_gcode": "; End G-code\nEND_PRINT",
|
||||
"machine_pause_gcode": "G5",
|
||||
"machine_start_gcode": "M117 Printing...\nM107 ; Turn off the fan\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nM104 S140\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n;G32 ;Load bed mesh\nG28 ;home\nG29 bed leveling\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG0 Z2.0 F600;\nG0 X50 Y10 F8000;\nG92 E0.0 ; reset extruder distance position\nG0 Z0.4 F600;\nG1 X100.0 E10 F3000.0 ; intro line\nG92 E0.0 ; reset extruder distance position\nG1 X200.0 E15 F3000.0 ; intro line\nG92 E0.0 ; reset extruder distance position\nG0 Z0.8 F600;\nG1 X100.0 E15 F3000.0 ; intro line\nG1 Z0.4 F600 ;Wipe\nG0 Y12 F6000 ;Wipe\nG1 X100 F6000 ;Wipe\nG0 Y8 F12000 ;Wipe\nG1 X200 F6000 ;Wipe\nG1 X190 Y12 F6000 ;Wipe\nG1 X180 Y8 F6000 ;Wipe\nG1 X170 Y12 F6000 ;Wipe\nG1 X160 Y8 F6000 ;Wipe\nG1 X150 Y12 F6000 ;Wipe\n;G0 Z2.0 F600;\nG92 E0.0 ; reset extruder distance position\n;START_PRINT",
|
||||
"purge_in_prime_tower": "0",
|
||||
"time_lapse_gcode": ";TIMELAPSE_TAKE_FRAME",
|
||||
"printable_height": "250",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"250x0",
|
||||
"250x250",
|
||||
"0x250"
|
||||
],
|
||||
"deretraction_speed": [
|
||||
"0"
|
||||
],
|
||||
"extruder_clearance_height_to_lid": "140",
|
||||
"extruder_clearance_height_to_rod": "36",
|
||||
"extruder_clearance_radius": "65",
|
||||
"machine_max_acceleration_e": [
|
||||
"20000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_retracting": [
|
||||
"15000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_z": [
|
||||
"100",
|
||||
"200"
|
||||
],
|
||||
"machine_max_jerk_e": [
|
||||
"1",
|
||||
"2.5"
|
||||
],
|
||||
"machine_max_jerk_x": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_jerk_y": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_speed_e": [
|
||||
"25",
|
||||
"25"
|
||||
],
|
||||
"machine_max_speed_x": [
|
||||
"500",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_y": [
|
||||
"500",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_z": [
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"retract_before_wipe": [
|
||||
"100%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.5"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"2"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"thumbnails": "300x300/PNG",
|
||||
"z_hop": [
|
||||
"0"
|
||||
],
|
||||
"upward_compatible_machine": []
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "machine_model",
|
||||
"name": "Goofoo GP1",
|
||||
"nozzle_diameter": "0.4",
|
||||
"bed_model": "Goofoo-GP1.stl",
|
||||
"bed_texture": "Goofoo-GP1-texture.svg",
|
||||
"family": "Goofoo",
|
||||
"machine_tech": "FFF",
|
||||
"model_id": "V003",
|
||||
"default_materials": "Goofoo ABS @System"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "Goofoo TurboM 0.4 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "Wmdn5zTy1HH93Q5d",
|
||||
"instantiation": "true",
|
||||
"nozzle_diameter": [
|
||||
"0.4"
|
||||
],
|
||||
"nozzle_type": "brass",
|
||||
"printer_model": "Goofoo TurboM",
|
||||
"printer_variant": "0.4",
|
||||
"default_filament_profile": [
|
||||
"Goofoo ABS @System"
|
||||
],
|
||||
"default_print_profile": "0.20mm Standard @Goofoo TurboM",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"230x0",
|
||||
"230x200",
|
||||
"0x200"
|
||||
],
|
||||
"extruder_clearance_height_to_lid": "350",
|
||||
"extruder_clearance_height_to_rod": "60",
|
||||
"extruder_clearance_radius": "50",
|
||||
"machine_end_gcode": "M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG92 E0.0 ; reset extruder distance position;\nG1 E-1 F2100 ; retract\nG28 X Y; home X Y axis\n;M84 ; disable motors\nM107 ; turn off fan\n;SET_VELOCITY_LIMIT ACCEL_TO_DECEL=4000",
|
||||
"machine_max_jerk_z": [
|
||||
"3",
|
||||
"0.4"
|
||||
],
|
||||
"machine_start_gcode": "M107 ; Turn off the fan\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\n\n\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG28 ;home\n\nG1 X2 Y10 F3000;\n\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG1 Z0.28 F240\n\nG92 E0\n\nG1 Y140 E10 F1500 ; prime the nozzle\n\nG1 X2.3 F5000\nG92 E0\n\nG1 Y10 E10 F1200 ; prime the nozzle\n;G0 Z2.0 F600;\nG92 E0.0 ; reset extruder distance position;\nM82\n;SET_PRESSURE_ADVANCE ADVANCE=0.05\n;SET_VELOCITY_LIMIT ACCEL_TO_DECEL=10000\n",
|
||||
"printable_height": "200",
|
||||
"z_hop": [
|
||||
"0"
|
||||
],
|
||||
"machine_max_speed_e": [
|
||||
"25",
|
||||
"25"
|
||||
],
|
||||
"machine_max_speed_x": [
|
||||
"500",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_y": [
|
||||
"500",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_z": [
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"upward_compatible_machine": []
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "machine_model",
|
||||
"name": "Goofoo TurboM",
|
||||
"nozzle_diameter": "0.4",
|
||||
"bed_model": "Goofoo-TurboM.stl",
|
||||
"bed_texture": "Goofoo-TurboM-texture.svg",
|
||||
"family": "Goofoo",
|
||||
"machine_tech": "FFF",
|
||||
"model_id": "V002",
|
||||
"default_materials": "Goofoo ABS @System"
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "Goofoo Velo+ 0.2 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "wSr6VNECZHekeNRi",
|
||||
"instantiation": "true",
|
||||
"nozzle_diameter": [
|
||||
"0.2"
|
||||
],
|
||||
"nozzle_type": "hardened_steel",
|
||||
"printer_model": "Goofoo Velo+",
|
||||
"printer_variant": "0.2",
|
||||
"default_filament_profile": [
|
||||
"Goofoo ABS @System"
|
||||
],
|
||||
"default_print_profile": "0.10mm Standard @Goofoo Velo+",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"600x0",
|
||||
"600x500",
|
||||
"0x500"
|
||||
],
|
||||
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
|
||||
"printable_height": "600",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0",
|
||||
"change_filament_gcode": "PAUSE",
|
||||
"deretraction_speed": [
|
||||
"0"
|
||||
],
|
||||
"extruder_clearance_height_to_lid": "350",
|
||||
"extruder_clearance_height_to_rod": "60",
|
||||
"extruder_clearance_radius": "50",
|
||||
"machine_max_acceleration_e": [
|
||||
"20000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_retracting": [
|
||||
"15000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_z": [
|
||||
"100",
|
||||
"200"
|
||||
],
|
||||
"machine_max_jerk_e": [
|
||||
"1",
|
||||
"2.5"
|
||||
],
|
||||
"machine_max_jerk_x": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_jerk_y": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_speed_e": [
|
||||
"50",
|
||||
"25"
|
||||
],
|
||||
"machine_max_speed_x": [
|
||||
"730",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_y": [
|
||||
"730",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] ; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
|
||||
|
||||
"retract_before_wipe": [
|
||||
"100%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.5"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"2"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"thumbnails": "300x300/PNG",
|
||||
"z_hop": [
|
||||
"0"
|
||||
],
|
||||
"machine_max_acceleration_travel": [
|
||||
"10000",
|
||||
"10000"
|
||||
],
|
||||
"max_layer_height": [
|
||||
"0.16"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.04"
|
||||
],
|
||||
"upward_compatible_machine": []
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "Goofoo Velo+ 0.4 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "XzHz1vNOYg3Ofe8X",
|
||||
"instantiation": "true",
|
||||
"nozzle_diameter": [
|
||||
"0.4"
|
||||
],
|
||||
"nozzle_type": "hardened_steel",
|
||||
"printer_model": "Goofoo Velo+",
|
||||
"printer_variant": "0.4",
|
||||
"default_filament_profile": [
|
||||
"Goofoo ABS @System"
|
||||
],
|
||||
"default_print_profile": "0.20mm Standard @Goofoo Velo+",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"600x0",
|
||||
"600x500",
|
||||
"0x500"
|
||||
],
|
||||
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
|
||||
"printable_height": "600",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0",
|
||||
"change_filament_gcode": "PAUSE",
|
||||
"deretraction_speed": [
|
||||
"0"
|
||||
],
|
||||
"extruder_clearance_height_to_lid": "350",
|
||||
"extruder_clearance_height_to_rod": "60",
|
||||
"extruder_clearance_radius": "50",
|
||||
"machine_max_acceleration_e": [
|
||||
"20000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_retracting": [
|
||||
"15000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_z": [
|
||||
"100",
|
||||
"200"
|
||||
],
|
||||
"machine_max_jerk_e": [
|
||||
"1",
|
||||
"2.5"
|
||||
],
|
||||
"machine_max_jerk_x": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_jerk_y": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_speed_e": [
|
||||
"50",
|
||||
"25"
|
||||
],
|
||||
"machine_max_speed_x": [
|
||||
"730",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_y": [
|
||||
"730",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] ; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
|
||||
|
||||
"retract_before_wipe": [
|
||||
"100%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.5"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"2"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"thumbnails": "300x300/PNG",
|
||||
"z_hop": [
|
||||
"0"
|
||||
],
|
||||
"machine_max_acceleration_travel": [
|
||||
"10000",
|
||||
"10000"
|
||||
],
|
||||
"upward_compatible_machine": []
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "Goofoo Velo+ 0.6 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "Pauu7JRq7u2OD6kv",
|
||||
"instantiation": "true",
|
||||
"nozzle_diameter": [
|
||||
"0.6"
|
||||
],
|
||||
"nozzle_type": "hardened_steel",
|
||||
"printer_model": "Goofoo Velo+",
|
||||
"printer_variant": "0.6",
|
||||
"default_filament_profile": [
|
||||
"Goofoo ABS @System"
|
||||
],
|
||||
"default_print_profile": "0.30mm Standard @Goofoo Velo+",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"600x0",
|
||||
"600x500",
|
||||
"0x500"
|
||||
],
|
||||
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
|
||||
"printable_height": "600",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0",
|
||||
"change_filament_gcode": "PAUSE",
|
||||
"deretraction_speed": [
|
||||
"0"
|
||||
],
|
||||
"extruder_clearance_height_to_lid": "350",
|
||||
"extruder_clearance_height_to_rod": "60",
|
||||
"extruder_clearance_radius": "50",
|
||||
"machine_max_acceleration_e": [
|
||||
"20000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_retracting": [
|
||||
"15000",
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_z": [
|
||||
"100",
|
||||
"200"
|
||||
],
|
||||
"machine_max_jerk_e": [
|
||||
"1",
|
||||
"2.5"
|
||||
],
|
||||
"machine_max_jerk_x": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_jerk_y": [
|
||||
"5",
|
||||
"9"
|
||||
],
|
||||
"machine_max_speed_e": [
|
||||
"50",
|
||||
"25"
|
||||
],
|
||||
"machine_max_speed_x": [
|
||||
"730",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_y": [
|
||||
"730",
|
||||
"200"
|
||||
],
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] ; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
|
||||
|
||||
"retract_before_wipe": [
|
||||
"100%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.5"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"2"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"thumbnails": "300x300/PNG",
|
||||
"z_hop": [
|
||||
"0"
|
||||
],
|
||||
"machine_max_acceleration_travel": [
|
||||
"10000",
|
||||
"10000"
|
||||
],
|
||||
"max_layer_height": [
|
||||
"0.4"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.12"
|
||||
],
|
||||
"upward_compatible_machine": []
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "Goofoo Velo+ Tool 0.4",
|
||||
"inherits": "Goofoo Velo+ 0.4 nozzle",
|
||||
"from": "system",
|
||||
"setting_id": "ww39WeaF5nYks1em",
|
||||
"instantiation": "true",
|
||||
"nozzle_diameter": [
|
||||
"0.4",
|
||||
"0.4"
|
||||
],
|
||||
"printer_model": "Goofoo Velo+ Tool",
|
||||
"change_filament_gcode": "T[next_extruder]\n;M104 S[nozzle_temperature_initial_layer] T[next_extruder]; 正式设置喷嘴温度(与切片设置一致)\n;M109 S[nozzle_temperature_initial_layer] T[next_extruder] ; 等待喷嘴温度稳定\n",
|
||||
"default_nozzle_volume_type": [
|
||||
"Standard",
|
||||
"Standard"
|
||||
],
|
||||
"deretraction_speed": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"extruder_printable_height": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"extruder_type": [
|
||||
"Direct Drive",
|
||||
"Direct Drive"
|
||||
],
|
||||
"extruder_variant_list": [
|
||||
"Direct Drive Standard",
|
||||
"Direct Drive Standard"
|
||||
],
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nT0\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
|
||||
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 T0 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nM104 S140 T1\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] T0 ; 正式设置喷嘴温度(与切片设置一致)\nM104 S[nozzle_temperature_initial_layer] T1 ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] T0; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] T0 ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零\nG1 Z20 F240 ; Z轴抬升\nG1 X280 Y10 F3000 ; 移动至起始位置\nT1\nM104 S[nozzle_temperature_initial_layer] T1 ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] T1; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] T1; 等待喷嘴温度稳定\nG4 S10 ; 预热等待10秒\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X282.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
|
||||
"max_layer_height": [
|
||||
"0.32",
|
||||
"0.32"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_flush_dataset": [
|
||||
"nil",
|
||||
"0"
|
||||
],
|
||||
"nozzle_type": [
|
||||
"nil",
|
||||
"hardened_steel"
|
||||
],
|
||||
"nozzle_volume": [
|
||||
"nil",
|
||||
"0"
|
||||
],
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"300x0",
|
||||
"300x300",
|
||||
"0x300"
|
||||
],
|
||||
"printer_extruder_id": [
|
||||
"1",
|
||||
"2"
|
||||
],
|
||||
"printer_extruder_variant": [
|
||||
"Direct Drive Standard",
|
||||
"Direct Drive Standard"
|
||||
],
|
||||
"purge_in_prime_tower": "0",
|
||||
"retract_before_wipe": [
|
||||
"100%",
|
||||
"100%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"10"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.5",
|
||||
"0.5"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"2",
|
||||
"2"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"50",
|
||||
"50"
|
||||
],
|
||||
"single_extruder_multi_material": "0",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Slope Lift",
|
||||
"Slope Lift"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "machine_model",
|
||||
"name": "Goofoo Velo+ Tool",
|
||||
"nozzle_diameter": "0.4",
|
||||
"bed_model": "Goofoo-Velo+.stl",
|
||||
"bed_texture": "Goofoo-Velo+-texture.svg",
|
||||
"family": "Goofoo",
|
||||
"machine_tech": "FFF",
|
||||
"model_id": "V006",
|
||||
"default_materials": "Goofoo ABS @System"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "machine_model",
|
||||
"name": "Goofoo Velo+",
|
||||
"nozzle_diameter": "0.2;0.4;0.6",
|
||||
"bed_model": "Goofoo-Velo+.stl",
|
||||
"bed_texture": "Goofoo-Velo+-texture.svg",
|
||||
"family": "Goofoo",
|
||||
"machine_tech": "FFF",
|
||||
"model_id": "V001",
|
||||
"default_materials": "Goofoo ABS @System"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "fdm_klipper_common",
|
||||
"inherits": "fdm_machine_common",
|
||||
"from": "system",
|
||||
"instantiation": "false",
|
||||
"gcode_flavor": "klipper",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n\n",
|
||||
"machine_start_gcode": "G90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nM140 S{first_layer_bed_temperature[0]} ; set bed temp\nM104 S140 ; set temporary nozzle temp to prevent oozing\nG4 S10 ; wait 10s for preheating\nG28 ; home all axes\nG1 Z50 F240 ; raise Z axis\nG1 X2 Y10 F3000 ; move to start position\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp\nG1 Z0.28 F240 ; lower nozzle to print height\nG92 E0 ; reset extrusion distance\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000 ; slight X adjustment\nG92 E0 ; reset extrusion distance\nG1 Y10 E10 F1200 ; prime again\nG92 E0 ; final extrusion reset",
|
||||
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
|
||||
"change_filament_gcode": "PAUSE",
|
||||
"machine_pause_gcode": "PAUSE"
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "fdm_machine_common",
|
||||
"from": "system",
|
||||
"instantiation": "false",
|
||||
"printer_technology": "FFF",
|
||||
"deretraction_speed": [
|
||||
"40"
|
||||
],
|
||||
"extruder_colour": [
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"machine_max_acceleration_e": [
|
||||
"5000"
|
||||
],
|
||||
"machine_max_acceleration_extruding": [
|
||||
"10000"
|
||||
],
|
||||
"machine_max_acceleration_retracting": [
|
||||
"1000"
|
||||
],
|
||||
"machine_max_acceleration_x": [
|
||||
"10000"
|
||||
],
|
||||
"machine_max_acceleration_y": [
|
||||
"10000"
|
||||
],
|
||||
"machine_max_acceleration_z": [
|
||||
"500"
|
||||
],
|
||||
"machine_max_speed_e": [
|
||||
"60"
|
||||
],
|
||||
"machine_max_speed_x": [
|
||||
"500"
|
||||
],
|
||||
"machine_max_speed_y": [
|
||||
"500"
|
||||
],
|
||||
"machine_max_speed_z": [
|
||||
"10"
|
||||
],
|
||||
"machine_max_jerk_e": [
|
||||
"5"
|
||||
],
|
||||
"machine_max_jerk_x": [
|
||||
"8"
|
||||
],
|
||||
"machine_max_jerk_y": [
|
||||
"8"
|
||||
],
|
||||
"machine_max_jerk_z": [
|
||||
"0.4"
|
||||
],
|
||||
"machine_min_extruding_rate": [
|
||||
"0"
|
||||
],
|
||||
"machine_min_travel_rate": [
|
||||
"0"
|
||||
],
|
||||
"max_layer_height": [
|
||||
"0.32"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08"
|
||||
],
|
||||
"printable_height": "250",
|
||||
"extruder_clearance_radius": "65",
|
||||
"extruder_clearance_height_to_rod": "36",
|
||||
"extruder_clearance_height_to_lid": "140",
|
||||
"nozzle_diameter": [
|
||||
"0.4"
|
||||
],
|
||||
"printer_settings_id": "",
|
||||
"printer_variant": "0.4",
|
||||
"retraction_minimum_travel": [
|
||||
"2"
|
||||
],
|
||||
"retract_before_wipe": [
|
||||
"70%"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1"
|
||||
],
|
||||
"retraction_length": [
|
||||
"1"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"0"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"60"
|
||||
],
|
||||
"single_extruder_multi_material": "1",
|
||||
"change_filament_gcode": "",
|
||||
"wipe": [
|
||||
"1"
|
||||
],
|
||||
"default_print_profile": "",
|
||||
"machine_start_gcode": "G0 Z20 F9000\nG92 E0; G1 E-10 F1200\nG28\nM970 Q1 A10 B10 C130 K0\nM970 Q1 A10 B131 C250 K1\nM974 Q1 S1 P0\nM970 Q0 A10 B10 C130 H20 K0\nM970 Q0 A10 B131 C250 K1\nM974 Q0 S1 P0\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nG29 ;Home\nG90;\nG92 E0 ;Reset Extruder \nG1 Z2.0 F3000 ;Move Z Axis up \nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM109 S205;\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder \nG1 X110 Y110 Z2.0 F3000 ;Move Z Axis up",
|
||||
"machine_end_gcode": "M400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-4.0 F3600; retract \nG91\nG1 Z3;\nM104 S0 ; turn off hotend\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nG90 \nG0 X110 Y200 F3600 \nprint_end",
|
||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
|
||||
"machine_pause_gcode": "M601"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.10mm Standard @Goofoo Velo+",
|
||||
"inherits": "0.20mm Standard @Goofoo Velo+",
|
||||
"from": "system",
|
||||
"setting_id": "dJV4bTrLbOPzW2YB",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Goofoo Velo+ 0.2 nozzle"
|
||||
],
|
||||
"layer_height": "0.1",
|
||||
"initial_layer_print_height": "0.1",
|
||||
"bottom_shell_layers": "6",
|
||||
"top_shell_layers": "12",
|
||||
"wall_loops": "4",
|
||||
"line_width": "0.22",
|
||||
"initial_layer_line_width": "0.25",
|
||||
"inner_wall_line_width": "0.22",
|
||||
"outer_wall_line_width": "0.22",
|
||||
"sparse_infill_line_width": "0.22",
|
||||
"internal_solid_infill_line_width": "0.22",
|
||||
"top_surface_line_width": "0.22",
|
||||
"support_line_width": "0.22",
|
||||
"support_top_z_distance": "0.1",
|
||||
"support_bottom_z_distance": "0.1"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.20mm Standard @Goofoo GP1",
|
||||
"inherits": "fdm_process_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "zrscQBUxp6L7BlQ9",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Goofoo GP1 0.4 nozzle"
|
||||
],
|
||||
"layer_height": "0.2",
|
||||
"accel_to_decel_enable": "0",
|
||||
"bridge_acceleration": "100%",
|
||||
"bridge_speed": "100",
|
||||
"brim_type": "no_brim",
|
||||
"gap_infill_speed": "250",
|
||||
"initial_layer_acceleration": "1000",
|
||||
"initial_layer_infill_speed": "100",
|
||||
"initial_layer_speed": "70",
|
||||
"inner_wall_speed": "250",
|
||||
"internal_bridge_speed": "200%",
|
||||
"internal_solid_infill_speed": "250",
|
||||
"outer_wall_acceleration": "5000",
|
||||
"outer_wall_speed": "100",
|
||||
"overhang_4_4_speed": "0",
|
||||
"reduce_crossing_wall": "1",
|
||||
"skirt_distance": "6",
|
||||
"skirt_height": "1",
|
||||
"skirt_loops": "1",
|
||||
"sparse_infill_pattern": "grid",
|
||||
"sparse_infill_speed": "250",
|
||||
"top_surface_acceleration": "5000",
|
||||
"top_surface_speed": "200",
|
||||
"travel_acceleration": "5000"
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.20mm Standard @Goofoo TurboM",
|
||||
"inherits": "fdm_process_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "LVXxUtAcYGCY6irA",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Goofoo TurboM 0.4 nozzle"
|
||||
],
|
||||
"layer_height": "0.2",
|
||||
"bridge_acceleration": "2000",
|
||||
"bridge_speed": "60",
|
||||
"brim_type": "no_brim",
|
||||
"default_acceleration": "10000",
|
||||
"enable_support": "1",
|
||||
"exclude_object": "0",
|
||||
"gap_infill_speed": "200",
|
||||
"infill_anchor": "600%",
|
||||
"infill_combination": "1",
|
||||
"infill_wall_overlap": "15%",
|
||||
"initial_layer_acceleration": "1000",
|
||||
"initial_layer_line_width": "0.45",
|
||||
"initial_layer_speed": "60",
|
||||
"inner_wall_acceleration": "3000",
|
||||
"inner_wall_line_width": "0.42",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_acceleration": "3000",
|
||||
"internal_solid_infill_line_width": "0.42",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"line_width": "0.42",
|
||||
"min_skirt_length": "0",
|
||||
"minimum_sparse_infill_area": "70",
|
||||
"only_one_wall_top": "1",
|
||||
"outer_wall_acceleration": "2500",
|
||||
"outer_wall_line_width": "0.42",
|
||||
"outer_wall_speed": "100",
|
||||
"reduce_crossing_wall": "1",
|
||||
"skirt_distance": "6",
|
||||
"skirt_height": "1",
|
||||
"skirt_loops": "4",
|
||||
"small_perimeter_speed": "200",
|
||||
"sparse_infill_acceleration": "3000",
|
||||
"sparse_infill_line_width": "0.42",
|
||||
"sparse_infill_pattern": "grid",
|
||||
"sparse_infill_speed": "150",
|
||||
"support_base_pattern": "rectilinear",
|
||||
"support_interface_bottom_layers": "-1",
|
||||
"support_interface_pattern": "rectilinear",
|
||||
"support_interface_spacing": "0",
|
||||
"support_interface_speed": "100",
|
||||
"support_interface_top_layers": "3",
|
||||
"support_line_width": "0.35",
|
||||
"support_object_xy_distance": "0.21",
|
||||
"support_speed": "100",
|
||||
"thick_bridges": "1",
|
||||
"top_shell_layers": "6",
|
||||
"top_shell_thickness": "0",
|
||||
"top_surface_acceleration": "2500",
|
||||
"top_surface_line_width": "0.42",
|
||||
"top_surface_speed": "150",
|
||||
"travel_acceleration": "10000",
|
||||
"travel_speed": "200",
|
||||
"wall_generator": "classic",
|
||||
"wall_loops": "2",
|
||||
"wall_sequence": "outer wall/inner wall"
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.20mm Standard @Goofoo Velo+",
|
||||
"inherits": "fdm_process_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "iWjynhCcvbF8MWev",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Goofoo Velo+ 0.4 nozzle",
|
||||
"Goofoo Velo+ Tool 0.4"
|
||||
],
|
||||
"layer_height": "0.2",
|
||||
"initial_layer_print_height": "0.2",
|
||||
"bottom_shell_layers": "3",
|
||||
"top_shell_layers": "6",
|
||||
"bridge_acceleration": "2000",
|
||||
"bridge_speed": "60",
|
||||
"brim_type": "no_brim",
|
||||
"default_acceleration": "10000",
|
||||
"enable_support": "1",
|
||||
"exclude_object": "0",
|
||||
"gap_infill_speed": "200",
|
||||
"infill_anchor": "600%",
|
||||
"infill_combination": "1",
|
||||
"infill_wall_overlap": "15%",
|
||||
"initial_layer_acceleration": "1000",
|
||||
"initial_layer_line_width": "0.45",
|
||||
"initial_layer_speed": "60",
|
||||
"inner_wall_acceleration": "3000",
|
||||
"inner_wall_line_width": "0.42",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_acceleration": "3000",
|
||||
"internal_solid_infill_line_width": "0.42",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"line_width": "0.42",
|
||||
"min_skirt_length": "0",
|
||||
"minimum_sparse_infill_area": "70",
|
||||
"only_one_wall_top": "1",
|
||||
"outer_wall_acceleration": "2500",
|
||||
"outer_wall_line_width": "0.42",
|
||||
"outer_wall_speed": "100",
|
||||
"reduce_crossing_wall": "1",
|
||||
"skirt_distance": "6",
|
||||
"skirt_height": "1",
|
||||
"skirt_loops": "4",
|
||||
"small_perimeter_speed": "200",
|
||||
"sparse_infill_acceleration": "3000",
|
||||
"sparse_infill_line_width": "0.42",
|
||||
"sparse_infill_pattern": "grid",
|
||||
"sparse_infill_speed": "150",
|
||||
"support_base_pattern": "rectilinear",
|
||||
"support_interface_bottom_layers": "-1",
|
||||
"support_interface_pattern": "rectilinear",
|
||||
"support_interface_spacing": "0",
|
||||
"support_interface_speed": "100",
|
||||
"support_interface_top_layers": "3",
|
||||
"support_line_width": "0.35",
|
||||
"support_object_xy_distance": "0.21",
|
||||
"support_speed": "100",
|
||||
"thick_bridges": "1",
|
||||
"top_shell_thickness": "0",
|
||||
"top_surface_acceleration": "2500",
|
||||
"top_surface_line_width": "0.42",
|
||||
"top_surface_speed": "150",
|
||||
"travel_acceleration": "10000",
|
||||
"travel_speed": "300",
|
||||
"wall_generator": "classic",
|
||||
"wall_loops": "2",
|
||||
"wall_sequence": "outer wall/inner wall"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.30mm Standard @Goofoo Velo+",
|
||||
"inherits": "fdm_process_klipper_common",
|
||||
"from": "system",
|
||||
"setting_id": "mi8ogYOYpqb2x60z",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Goofoo Velo+ 0.6 nozzle"
|
||||
],
|
||||
"initial_layer_print_height": "0.3",
|
||||
"layer_height": "0.3"
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "fdm_process_common",
|
||||
"from": "system",
|
||||
"instantiation": "false",
|
||||
"seam_position": "aligned",
|
||||
"resolution": "0.012",
|
||||
"elefant_foot_compensation": "0.2",
|
||||
"precise_outer_wall": "1",
|
||||
"ironing_type": "no ironing",
|
||||
"ironing_speed": "30",
|
||||
"ironing_flow": "10%",
|
||||
"ironing_spacing": "0.15",
|
||||
"reduce_crossing_wall": "1",
|
||||
"max_travel_detour_distance": "0",
|
||||
"detect_overhang_wall": "1",
|
||||
"wall_loops": "3",
|
||||
"top_surface_pattern": "monotonicline",
|
||||
"top_shell_layers": "5",
|
||||
"top_shell_thickness": "0.7",
|
||||
"bottom_surface_pattern": "monotonic",
|
||||
"bottom_shell_layers": "4",
|
||||
"bottom_shell_thickness": "0.5",
|
||||
"sparse_infill_density": "15%",
|
||||
"sparse_infill_pattern": "crosshatch",
|
||||
"infill_wall_overlap": "23%",
|
||||
"infill_direction": "45",
|
||||
"minimum_sparse_infill_area": "15",
|
||||
"infill_combination": "0",
|
||||
"ensure_vertical_shell_thickness": "1",
|
||||
"initial_layer_speed": "50",
|
||||
"initial_layer_infill_speed": "50",
|
||||
"initial_layer_travel_speed": "100%",
|
||||
"outer_wall_speed": "125",
|
||||
"inner_wall_speed": "250",
|
||||
"sparse_infill_speed": "250",
|
||||
"internal_solid_infill_speed": "200",
|
||||
"top_surface_speed": "150",
|
||||
"gap_infill_speed": "150",
|
||||
"support_speed": "125",
|
||||
"support_interface_speed": "80",
|
||||
"enable_overhang_speed": "1",
|
||||
"overhang_1_4_speed": "0",
|
||||
"overhang_2_4_speed": "50",
|
||||
"overhang_3_4_speed": "25",
|
||||
"overhang_4_4_speed": "15",
|
||||
"bridge_speed": "50",
|
||||
"travel_speed": "300",
|
||||
"default_acceleration": "2500",
|
||||
"outer_wall_acceleration": "500",
|
||||
"inner_wall_acceleration": "500",
|
||||
"bridge_acceleration": "500",
|
||||
"travel_acceleration": "2500",
|
||||
"default_jerk": "15",
|
||||
"outer_wall_jerk": "10",
|
||||
"inner_wall_jerk": "15",
|
||||
"infill_jerk": "15",
|
||||
"top_surface_jerk": "12",
|
||||
"initial_layer_jerk": "12",
|
||||
"travel_jerk": "20",
|
||||
"enable_support": "0",
|
||||
"support_type": "normal(auto)",
|
||||
"support_threshold_angle": "30",
|
||||
"support_on_build_plate_only": "0",
|
||||
"raft_layers": "0",
|
||||
"support_filament": "0",
|
||||
"support_interface_filament": "0",
|
||||
"support_top_z_distance": "0.2",
|
||||
"support_base_pattern": "default",
|
||||
"support_base_pattern_spacing": "2.5",
|
||||
"support_interface_top_layers": "2",
|
||||
"support_interface_bottom_layers": "2",
|
||||
"support_interface_spacing": "0.5",
|
||||
"support_object_xy_distance": "0.5",
|
||||
"bridge_no_support": "0",
|
||||
"independent_support_layer_height": "1",
|
||||
"tree_support_branch_angle": "30",
|
||||
"tree_support_wall_count": "0",
|
||||
"skirt_loops": "2",
|
||||
"skirt_distance": "3",
|
||||
"skirt_height": "1",
|
||||
"brim_width": "5",
|
||||
"brim_object_gap": "0.1",
|
||||
"enable_prime_tower": "0",
|
||||
"prime_tower_width": "60",
|
||||
"wipe_tower_no_sparse_layers": "0",
|
||||
"print_sequence": "by layer",
|
||||
"spiral_mode": "0",
|
||||
"reduce_infill_retraction": "1",
|
||||
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}.gcode"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "fdm_process_klipper_common",
|
||||
"inherits": "fdm_process_common",
|
||||
"from": "system",
|
||||
"instantiation": "false",
|
||||
"default_acceleration": "5000",
|
||||
"top_surface_acceleration": "3000",
|
||||
"travel_acceleration": "7000",
|
||||
"inner_wall_acceleration": "5000",
|
||||
"outer_wall_acceleration": "3000",
|
||||
"initial_layer_acceleration": "500",
|
||||
"initial_layer_speed": "50",
|
||||
"initial_layer_infill_speed": "105",
|
||||
"outer_wall_speed": "120",
|
||||
"inner_wall_speed": "200",
|
||||
"internal_solid_infill_speed": "200",
|
||||
"top_surface_speed": "100",
|
||||
"gap_infill_speed": "100",
|
||||
"sparse_infill_speed": "200",
|
||||
"travel_speed": "350",
|
||||
"exclude_object": "1"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "OrcaFilamentLibrary",
|
||||
"version": "02.04.00.15",
|
||||
"version": "02.04.00.16",
|
||||
"force_update": "0",
|
||||
"description": "Orca Filament Library",
|
||||
"filament_list": [
|
||||
@@ -1396,6 +1396,10 @@
|
||||
"name": "addnorth ABS rABS",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth ABS rABS.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo ABS @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo ABS @base.json"
|
||||
},
|
||||
{
|
||||
"name": "NIT ABS @System",
|
||||
"sub_path": "filament/NIT/NIT ABS @System.json"
|
||||
@@ -1480,6 +1484,10 @@
|
||||
"name": "Elegoo ASA-CF @base",
|
||||
"sub_path": "filament/Elegoo/Elegoo ASA-CF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo ASA @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo ASA @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Overture ASA @BBL X1",
|
||||
"sub_path": "filament/Overture/BBL/Overture ASA @BBL X1.json"
|
||||
@@ -1636,10 +1644,22 @@
|
||||
"name": "addnorth PVDF Adamant S1",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PVDF Adamant S1.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PA @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PA @base.json"
|
||||
},
|
||||
{
|
||||
"name": "addnorth PA-CF Adura X",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PA-CF Adura X.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PA-CF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PA-CF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PA-GF10 @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PA-GF10 @base.json"
|
||||
},
|
||||
{
|
||||
"name": "INSLOGIC PA6-66 @BBL P2S",
|
||||
"sub_path": "filament/INSLOGIC/BBL/INSLOGIC PA6-66 @BBL P2S.json"
|
||||
@@ -1712,6 +1732,10 @@
|
||||
"name": "COEX PCTG PRIME @System",
|
||||
"sub_path": "filament/COEX/COEX PCTG PRIME @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PE @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PE @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Generic PE-CF @System",
|
||||
"sub_path": "filament/Generic PE-CF @System.json"
|
||||
@@ -2176,6 +2200,10 @@
|
||||
"name": "addnorth PETG rPETG Matte",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PETG rPETG Matte.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PETG @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PETG @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Generic PETG HF @System",
|
||||
"sub_path": "filament/Generic PETG HF @System.json"
|
||||
@@ -2236,6 +2264,10 @@
|
||||
"name": "eSUN PETG @System",
|
||||
"sub_path": "filament/eSUN/eSUN PETG @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PHA @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PHA @base.json"
|
||||
},
|
||||
{
|
||||
"name": "AliZ PLA @P1-X1",
|
||||
"sub_path": "filament/AliZ/BBL/AliZ PLA @P1-X1.json"
|
||||
@@ -3120,6 +3152,10 @@
|
||||
"name": "addnorth PLA rPLA RE-ADD",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PLA rPLA RE-ADD.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PLA @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PLA @base.json"
|
||||
},
|
||||
{
|
||||
"name": "addnorth PLA X-PLA High Speed",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PLA X-PLA High Speed.json"
|
||||
@@ -3136,6 +3172,10 @@
|
||||
"name": "addnorth PLA-CF Carbon Fiber",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PLA-CF Carbon Fiber.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PLA-CF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PLA-CF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "INSLOGIC PLA Pro @BBL P2S",
|
||||
"sub_path": "filament/INSLOGIC/BBL/INSLOGIC PLA Pro @BBL P2S.json"
|
||||
@@ -3820,6 +3860,10 @@
|
||||
"name": "FILL3D PPCF @System",
|
||||
"sub_path": "filament/FILL3D/FILL3D PPCF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PP @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PP @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Generic PP-CF @System",
|
||||
"sub_path": "filament/Generic PP-CF @System.json"
|
||||
@@ -3840,6 +3884,10 @@
|
||||
"name": "Bambu PVA @System",
|
||||
"sub_path": "filament/Bambu/Bambu PVA @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PVA @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PVA @base.json"
|
||||
},
|
||||
{
|
||||
"name": "FDplast SBS @System",
|
||||
"sub_path": "filament/FDplast/FDplast SBS @System.json"
|
||||
@@ -4112,6 +4160,14 @@
|
||||
"name": "addnorth TPU Pro Matte 95A",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth TPU Pro Matte 95A.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo 90A TPU @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo 90A TPU @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo 95A TPU @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo 95A TPU @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Overture TPU @BBL A1",
|
||||
"sub_path": "filament/Overture/BBL/Overture TPU @BBL A1.json"
|
||||
@@ -4156,10 +4212,30 @@
|
||||
"name": "Overture TPU @System",
|
||||
"sub_path": "filament/Overture/Overture TPU @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo ABS @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo ABS @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Elegoo ASA-CF @System",
|
||||
"sub_path": "filament/Elegoo/Elegoo ASA-CF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo ASA @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo ASA @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PA @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PA @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PA-CF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PA-CF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PA-GF10 @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PA-GF10 @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Elegoo PC-FR @System",
|
||||
"sub_path": "filament/Elegoo/Elegoo PC-FR @System.json"
|
||||
@@ -4176,6 +4252,14 @@
|
||||
"name": "COEX PCTG PRIME @BBL A1M 0.8 nozzle",
|
||||
"sub_path": "filament/COEX/BBL/COEX PCTG PRIME @BBL A1M 0.8 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PE @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PE @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PE-CF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PE-CF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "AliZ PETG-CF @P1-X1",
|
||||
"sub_path": "filament/AliZ/BBL/AliZ PETG-CF @P1-X1.json"
|
||||
@@ -4236,10 +4320,26 @@
|
||||
"name": "Fiberon PETG-ESD @BBL X1",
|
||||
"sub_path": "filament/Polymaker/BBL/Fiberon PETG-ESD @BBL X1.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PETG @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PETG @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PETG HF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PETG HF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "addnorth PETG-CF Rigid X",
|
||||
"sub_path": "filament/addnorth/BBL/addnorth PETG-CF Rigid X.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PETG-CF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PETG-CF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PHA @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PHA @System.json"
|
||||
},
|
||||
{
|
||||
"name": "COEX PLA @BBL A1M 0.2 nozzle",
|
||||
"sub_path": "filament/COEX/BBL/COEX PLA @BBL A1M 0.2 nozzle.json"
|
||||
@@ -4304,6 +4404,14 @@
|
||||
"name": "Elegoo Rapid PLA+ @System",
|
||||
"sub_path": "filament/Elegoo/Elegoo Rapid PLA+ @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PLA @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PLA @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PLA-CF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PLA-CF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Numakers PLA+ @BBL A1",
|
||||
"sub_path": "filament/Numakers/BBL/Numakers PLA+ @BBL A1.json"
|
||||
@@ -5188,9 +5296,61 @@
|
||||
"name": "COEX PLA+Silk @System",
|
||||
"sub_path": "filament/COEX/COEX PLA+Silk @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PLA Silk @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PLA Silk @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PP @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PP @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PP-CF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PP-CF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PP-GF @base",
|
||||
"sub_path": "filament/Goofoo/Goofoo PP-GF @base.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PVA @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PVA @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Elegoo Rapid TPU 95A @System",
|
||||
"sub_path": "filament/Elegoo/Elegoo Rapid TPU 95A @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo 90A TPU @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo 90A TPU @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo 95A TPU @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo 95A TPU @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PE-CF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PE-CF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PETG HF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PETG HF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PETG-CF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PETG-CF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PLA Silk @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PLA Silk @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PP-CF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PP-CF @System.json"
|
||||
},
|
||||
{
|
||||
"name": "Goofoo PP-GF @System",
|
||||
"sub_path": "filament/Goofoo/Goofoo PP-GF @System.json"
|
||||
}
|
||||
],
|
||||
"process_list": [],
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo 90A TPU @System",
|
||||
"inherits": "Goofoo 90A TPU @base",
|
||||
"from": "system",
|
||||
"setting_id": "tjq76AQe9SCzZVo6",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo 90A TPU @base",
|
||||
"inherits": "Generic TPU @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFlVOXX3",
|
||||
"instantiation": "false",
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"fan_min_speed": [
|
||||
"35"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"2"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"40"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"40"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"220"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"220"
|
||||
],
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"0"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"5"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"TPU"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo 95A TPU @System",
|
||||
"inherits": "Goofoo 95A TPU @base",
|
||||
"from": "system",
|
||||
"setting_id": "2YTvrE1gu1yHHTNM",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo 95A TPU @base",
|
||||
"inherits": "Generic TPU @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFk50t30",
|
||||
"instantiation": "false",
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"fan_min_speed": [
|
||||
"35"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"40"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"40"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"220"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"220"
|
||||
],
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"0"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"5"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"TPU"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo ABS @System",
|
||||
"inherits": "Goofoo ABS @base",
|
||||
"from": "system",
|
||||
"setting_id": "UeINgPGH4eaSJinC",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo ABS @base",
|
||||
"inherits": "Generic ABS @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFd3PmW4",
|
||||
"instantiation": "false",
|
||||
"close_fan_the_first_x_layers": [
|
||||
"1"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"110"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"ABS"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo ASA @System",
|
||||
"inherits": "Goofoo ASA @base",
|
||||
"from": "system",
|
||||
"setting_id": "9ohqNl44uygTPfS9",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo ASA @base",
|
||||
"inherits": "Generic ASA @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFyncHIG",
|
||||
"instantiation": "false",
|
||||
"filament_flow_ratio": [
|
||||
"0.93"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"100"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"ASA"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PA @System",
|
||||
"inherits": "Goofoo PA @base",
|
||||
"from": "system",
|
||||
"setting_id": "1ximJVgZZfGmGyzD",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PA @base",
|
||||
"inherits": "Generic PA @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFc2x7Ly",
|
||||
"instantiation": "false",
|
||||
"filament_max_volumetric_speed": [
|
||||
"12"
|
||||
],
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"1"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PA"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PA-CF @System",
|
||||
"inherits": "Goofoo PA-CF @base",
|
||||
"from": "system",
|
||||
"setting_id": "US4zznMNti8tLUHG",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PA-CF @base",
|
||||
"inherits": "Generic PA-CF @System",
|
||||
"from": "system",
|
||||
"filament_id": "OF7skcRj",
|
||||
"instantiation": "false",
|
||||
"filament_max_volumetric_speed": [
|
||||
"12"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PA-CF"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PA-GF10 @System",
|
||||
"inherits": "Goofoo PA-GF10 @base",
|
||||
"from": "system",
|
||||
"setting_id": "Lea3hf2lQG0M9eTC",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PA-GF10 @base",
|
||||
"inherits": "Generic PA-CF @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFtjqw2h",
|
||||
"instantiation": "false",
|
||||
"nozzle_temperature": [
|
||||
"230"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"1"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PA-GF"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PE @System",
|
||||
"inherits": "Goofoo PE @base",
|
||||
"from": "system",
|
||||
"setting_id": "muNxvgr0vdavMaOJ",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PE @base",
|
||||
"inherits": "Generic PE @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFAln723",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PE"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PE-CF @System",
|
||||
"inherits": "Goofoo PE-CF @base",
|
||||
"from": "system",
|
||||
"setting_id": "58fMbg6AClvalw5o",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PE-CF @base",
|
||||
"inherits": "Generic PE-CF @System",
|
||||
"from": "system",
|
||||
"filament_id": "OF4Ll1Sk",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PE-CF"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PETG @System",
|
||||
"inherits": "Goofoo PETG @base",
|
||||
"from": "system",
|
||||
"setting_id": "a9OKgJeoJgzfZiAB",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PETG @base",
|
||||
"inherits": "Generic PETG @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFHdIbiu",
|
||||
"instantiation": "false",
|
||||
"hot_plate_temp": [
|
||||
"80"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"80"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"240"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"240"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PETG"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PETG HF @System",
|
||||
"inherits": "Goofoo PETG HF @base",
|
||||
"from": "system",
|
||||
"setting_id": "eMjhTRf5qPeeqSgk",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PETG HF @base",
|
||||
"inherits": "Generic PETG HF @System",
|
||||
"from": "system",
|
||||
"filament_id": "OF5bjxyx",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PETG HF"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PETG-CF @System",
|
||||
"inherits": "Goofoo PETG-CF @base",
|
||||
"from": "system",
|
||||
"setting_id": "ULNFo6zjgjc5MEIa",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PETG-CF @base",
|
||||
"inherits": "Generic PETG-CF @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFo6Ff38",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PETG-CF"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PHA @System",
|
||||
"inherits": "Goofoo PHA @base",
|
||||
"from": "system",
|
||||
"setting_id": "cfdeMyqld72Lqh38",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PHA @base",
|
||||
"inherits": "Generic PHA @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFicmNhN",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PHA"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PLA @System",
|
||||
"inherits": "Goofoo PLA @base",
|
||||
"from": "system",
|
||||
"setting_id": "UFWRE1b3706Cu1Iq",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PLA @base",
|
||||
"inherits": "Generic PLA @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFoq0Cmt",
|
||||
"instantiation": "false",
|
||||
"hot_plate_temp": [
|
||||
"40"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"40"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"230"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PLA Silk @System",
|
||||
"inherits": "Goofoo PLA Silk @base",
|
||||
"from": "system",
|
||||
"setting_id": "2pW2NEoY4hFCkNun",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PLA Silk @base",
|
||||
"inherits": "Generic PLA Silk @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFpta2gc",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA Silk"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PLA-CF @System",
|
||||
"inherits": "Goofoo PLA-CF @base",
|
||||
"from": "system",
|
||||
"setting_id": "R0UMDUPY9ryat8gQ",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PLA-CF @base",
|
||||
"inherits": "Generic PLA-CF @System",
|
||||
"from": "system",
|
||||
"filament_id": "OFMNABGJ",
|
||||
"instantiation": "false",
|
||||
"filament_flow_ratio": [
|
||||
"0.98"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"40"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"40"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"240"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"240"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Goofoo"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA-CF"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "Goofoo PP @System",
|
||||
"inherits": "Goofoo PP @base",
|
||||
"from": "system",
|
||||
"setting_id": "TaB8JUtjJWgRcNrv",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": []
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user