Specyfikacja otwartego formatu
Rozszerzenie OXS: hardanger
Rozszerzenie formatu wzorów OXS (Open Cross Stitch) o haft hardanger — klostry, pasma cięcia, słupki, wypełnienia, ściegi powierzchniowe, picoty i koraliki — zapisane bez zmiany choćby jednego bajtu standardowych danych OXS. Każdy może je zaimplementować, w dowolnym programie, bez pytania o zgodę.
Słowa MUST, MUST NOT, SHOULD i MAY mają zwykłe znaczenie normatywne i celowo zostają po angielsku. Wszystkie nazwy elementów i atrybutów są dosłowne.
1. Zasady konstrukcyjne
- Tylko nowe elementy top-level. Rozszerzenie MUST NOT dodawać atrybutów do istniejących elementów OXS ani zmieniać znaczenia istniejących danych. Jedyna gwarancja, jaką daje XML, to pomijanie nieznanych elementów — nieznany atrybut na znanym elemencie nie jest bezpieczny.
- Sekcje standardowe nietknięte. Pełne krzyżyki zostają w
<fullstitches>, koraliki i węzełki w<ornaments_inc_knots_and_beads>, kontury w<backstitches>. Rozszerzenie tylko dodaje. - Plik jest samoopisujący. Wypełnienie niesie id katalogu oraz rozwiązaną geometrię (§7.4). Ten sam plik MUST renderować się identycznie po aktualizacji katalogu wypełnień u czytnika.
- Geometria wyliczalna nie jest zapisywana. Klasyfikacja regionów, pozycje kropek cięcia i kolejność faz są wyliczane (§9). Zapis nadmiarowy = drugie źródło prawdy.
- Współrzędne w nitkach, całkowite. Wyjątkiem są rozwiązane ścieżki i dwa rekordy zakotwiczone w punkcie (picot, koralik), gdzie ułamki są dozwolone — to geometria nitki w powietrzu, nie pozycja na siatce.
2. Układ współrzędnych
unit="thread"— jednostką jest jedna nitka tkaniny.threadsperunit="2"— ile nitek przypada na jedną komórkę krzyżykową. Czytnik MUST przeczytać tę wartość i MUST NOT zakładać 2 (na 25 ct even-weave szytym przez jedną nitkę bywa 1).origin="node"—(0,0)to lewy-górny węzeł siatki (dziurka), zgodnie z konwencją OXS dla backstitcha.- Koordy
stx_*są ZAWSZE 0-based. Część czytników OXS zgaduje, czy plik jest 1-based, i przesuwa sekcje standardowe; ta heurystyka MUST NOT być stosowana do elementówstx_*. Ich układ współrzędnych jest zadeklarowany tutaj i nie podlega zgadywaniu. - Przeliczenie: komórka
(cx, cy)↔ nitka(cx · threadsperunit, cy · threadsperunit). - Nitka k pasma zaczynającego się w
x1zajmuje przedział[x1+k, x1+k+1]; jej środek tox1+k+0.5. Potrzebne przy rysowaniu kropek cięcia (§9.2).
<stx_satin x="2" y="2" axis="h" count="5" span="4" role="kloster">.
Pięć ściegów zajmuje kolumny węzłów 2…6 — czyli cztery przedziały nitkowe, nie pięć.Dlaczego nitki. Hardanger jest natywnie liczony w nitkach, a
threadsperunit to jedna deklarowana konwersja. Współrzędna nitkowa jest przy tym
tożsama z reprezentacją w pamięci implementacji (pół-komórki fixed-point ×2), więc między plikiem
a modelem nie ma żadnego przeliczania.
3. Deklaracja rozszerzenia
<stx_extensions version="1" vendor="obateam"
spec="https://stitchtracker.obateam.com/oxs-ext/1">
<stx_feature id="hardanger" version="1" required="true" fallback="comment"
summary="12 kloster blocks, 6 cut bands, 12 bars, 5 fillings, 4 eyelets, 0 beads, 2 straight stitches, 4 picots" />
</stx_extensions>
| Atrybut | Znaczenie |
|---|---|
id | Rodzina technik. Wersja 1 definiuje dokładnie jedną: hardanger. |
version | Wersja definicji tej rodziny, niezależna od stx_extensions/@version. Mówi, czego plik faktycznie wymaga od czytnika — patrz §12. |
required | true = bez wsparcia wzór jest niekompletny; czytnik SHOULD ostrzec użytkownika. |
fallback | comment | none. Jak treść jest zasygnalizowana czytnikowi bez wsparcia (§4). |
summary | Generowane podsumowanie licznikowe, po angielsku, do pokazania użytkownikowi. Informacyjne — czytnik MUST NOT parsować go jako danych. |
Writer referencyjny emituje osiem liczników w stałej kolejności: kloster blocks,
cut bands, bars, fillings, eyelets (wszystkie
<stx_stitch>, nie tylko oczka), beads,
straight stitches, picots. fallback="none" znaczy, że w pliku
NIE MA markera — tak zapisuje się blok bez zapisywalnych rekordów.
<stx_feature> jest punktem rozszerzalności. Kolejne rodziny technik
(silkribbon, drawnthread, blackwork) dostają własny
<stx_feature> i własny blok top-level. Wersja 1 ich nie definiuje.
4. Fallback i wykrywanie utraty danych
Przy fallback="comment" writer MUST wygenerować dokładnie jeden
<commentbox>-marker, którego tekst zaczyna się od stałego
sentinela HARDANGER:.
<commentboxes>
<commentbox boxleft="4" boxtop="4" boxwidth="14" boxheight="14"
boxwords="HARDANGER: 12 kloster blocks, 6 cut bands, 12 bars, 5 fillings, 4 eyelets, 0 beads, 2 straight stitches, 4 picots. Chart incomplete without Hardanger support. Requires software with Hardanger support." />
</commentboxes>
- Atrybuty to
boxleft/boxtop/boxwidth/boxheight/boxwords— rzeczywista konwencja OXS, którą czytają i piszą istniejące implementacje. Element z innym zestawem nazw (x/y/width/height/text…) zostanie przez nie w całości pominięty. Jednostki to komórki (ułamki.5dozwolone):<commentboxes>jest sekcją standardową i zachowuje jednostki OXS. boxwordsMUST zaczynać się odHARDANGER:(wielkość liter znacząca), MUST być po angielsku (plik podróżuje) i MUST NOT zawierać instrukcji haftowania — to sygnał, nie treść wzoru. MUST NOT być pusty; istniejące parsery odrzucają komentarze bez tekstu.boxleft/boxtop/boxwidth/boxheightSHOULD obejmować bounding box hardangeru, w komórkach.
Wykrywanie utraty danych. Obcy program, który wczyta i zapisze plik, wyrzuci
elementy stx_* (nie zna ich), ale zachowa <commentboxes> (zna).
Sentinel jest więc samowystarczalny: detekcja nie zależy od <stx_extensions>,
które w takim round-tripie ginie razem z resztą stx_*.
marker HARDANGER: | blok <stx_hardanger> | Interpretacja |
|---|---|---|
| nie | nie | Plik nigdy nie miał hardangeru. |
| nie | tak | Plik kompletny (writer z fallback="none"). |
| tak | tak | Plik kompletny. |
| tak | nie | Plik STRACIŁ hardanger. Czytnik MUST ostrzec i MUST NOT cicho nadpisać oryginału. |
Synchronizacja markera. Marker jest artefaktem writera, nie treścią wzoru:
- czytnik pełny MUST rozpoznać go po prefiksie
HARDANGER:i MUST ukryć przed użytkownikiem — to nie jest zwykły komentarz i nie podlega edycji; - writer MUST emitować marker wtedy i tylko wtedy, gdy blok
<stx_hardanger>niesie rekordy ifallback="comment"; usunięcie całego hardangeru ze wzoru usuwa marker przy następnym zapisie; - w pliku MUST być co najwyżej jeden marker.
<backstitches>?
Backstitch jest ściegiem. Cień-zarys zostałby wyhaftowany jako kontur i dałby artefakt
wyglądający jak wzór, którym nie jest. Komentarz to tekst — nikt go nie wyhaftuje. Opcjonalny
objecttype="stx_shadow" MAY pojawić się w przyszłej wersji jako
przełącznik eksportu z domyślnym OFF; wersja 1 go nie definiuje.
5. Blok stx_hardanger
Dokument MUST zawierać co najwyżej jeden
<stx_hardanger>, jako rodzeństwo sekcji standardowych — jedno miejsce detekcji,
jedno miejsce pominięcia.
<stx_hardanger unit="thread" threadsperunit="2" origin="node">
<stx_threads>…</stx_threads>
<stx_satins>…</stx_satins>
<stx_cuts>…</stx_cuts>
<stx_bars>…</stx_bars>
<stx_fillings>…</stx_fillings>
<stx_surface>…</stx_surface>
<stx_beads>…</stx_beads>
<stx_picots>…</stx_picots>
</stx_hardanger>
Wszystkie kolekcje są opcjonalne. Ich kolejność jest nieznacząca; czytnik MUST NOT jej zakładać.
Deklaracja układu współrzędnych jest obowiązkowa. unit="thread",
origin="node" i całkowite threadsperunit ≥ 1
MUST być na bloku. Czytnik, który nie potrafi ich odczytać (brak, inna
wartość, wartość spoza domeny), MUST odrzucić cały blok,
a nie zgadywać domyślnych: rekord bez zadeklarowanego układu jest rekordem bez znaczenia, a nie
rekordem w układzie domyślnym.
Rekordy MUST być bezpośrednimi dziećmi swojej kolekcji (jeden poziom pod blokiem).
Czytnik MUST ignorować rekordy zagnieżdżone głębiej oraz — gdy plik łamie
regułę jednego bloku — wszystko poza pierwszym <stx_hardanger>. Wyjątkiem jest
<stx_path>, który z definicji jest dzieckiem rekordu.
6. Nici
<stx_threads>
<stx_thread palindex="2" weight="perle8" />
<stx_thread palindex="3" weight="perle12" />
</stx_threads>
palindex odnosi się do standardowej palety OXS. weight ∈
perle3 | perle5 | perle8 | perle12 | floss | other. Grubość nici jest realną własnością
wzoru hardanger (klostry perle 8, słupki i oczka perle 12), nie kosmetyką: wpływa i na render,
i na listę zakupów.
Kolekcja opisuje nici użyte w rekordach hardangeru, a nie całą paletę: nić, której wszystkie rekordy zniknęły, wypada z niej przy następnym zapisie. Koraliki są wyłączone — koralik (§7.8) nie jest nicią i nie ma grubości.
Waga wynika z produktu, nie z roli rekordu. Grubość kordonka jest częścią numeru
nici („DMC Pearl 8”), więc writer wyprowadza ją z marki; reguła rzemiosła („satyna grubszą, reszta
cieńszą”) mówi, KTÓRĄ nić wybrać, a nie jaką grubość ma nić już wybrana — konkretna para zależy od
splotu tkaniny (22 ct → 5 + 8, 28 ct → 8 + 12). Writer SHOULD więc wyliczać
wagę wyłącznie dla nici, która wpisu jeszcze nie ma, i MUST zachować wagę
wczytaną z pliku: autorytatywne przeliczanie zamienia zaimportowane perle8 przy
nierozpoznanej marce na other po pierwszej edycji, czyli cicho traci dane interopu.
7. Prymitywy
7.1 stx_satin — pas satynowy, w tym klostr
<stx_satin x="12" y="8" axis="h" count="5" span="4"
palindex="2" role="kloster" dir="down" />
| Atrybut | Znaczenie |
|---|---|
x, y | Lewy-górny węzeł bounding boxu, w nitkach. |
axis | h = ściegi ułożone obok siebie wzdłuż x (każdy ścieg biegnie w y); v = odwrotnie. |
count | Liczba ściegów satynowych. |
span | Długość jednego ściegu, w nitkach. |
role | kloster | satin | edge |
dir | up | down | left | right — strona, którą pas zabezpiecza. |
role="kloster" znaczy „autor tnie przy tym bloku” — to decyzja autora
zapisana w rekordzie, a nie opis kształtu. Książka mówi to wprost: „klosters and longer satin
stitch blocks can be put together to form cutwork areas” (s. 18), „sometimes there are more
than five satin stitches to cut beside” (s. 34).
Kanoniczny klostr to count="5", span="4" — bounding box
4×4 nitki, bo pięć ściegów zajmuje kolumny węzłów x … x+4, czyli cztery przedziały
nitkowe. To szczególny przypadek, nie warunek: legalne obramowanie wycięcia ma
count ≥ 2 i span ≥ 1, a liczba nitek wychodzących z czoła to zawsze
count − 1, więc pasma, pary i okienka liczą się tą samą matematyką. Blok jednościegowy
nie oddaje żadnej nitki i obramowaniem nie jest; role="edge" (obrzeże wykończeniowe)
z okienkiem nie graniczy.
dir jest znaczące dla walidacji i lustrowania, nie tylko dla renderu: wskazuje
krawędź, przy której pas zabezpiecza przecięte końce nitek. Lustrowanie pasa
MUST odwrócić dir.
7.2 stx_cut — pasmo usuniętych nitek
<stx_cut dir="v" x1="12" y1="12" x2="16" y2="32" derived="1" />
| Atrybut | Znaczenie |
|---|---|
dir | Kierunek biegu usuniętych nitek: v = pionowe, h = poziome. |
x1,y1,x2,y2 | Bounding box pasma, w nitkach; x1<x2, y1<y2. |
derived | 1 = pasmo wyliczone z pary klostrów; 0 = jawny override autora. |
To nie jest prostokąt otworu. Otwór jest skutkiem, nie daną. Pasmo opisuje
fizyczną czynność: „nitki biegnące w kierunku dir w tym obszarze zostały
wyciągnięte”.
Uzasadnienie. Prostokąt-otwór nie potrafi opisać obszaru, w którym usunięto nitki
tylko jednego kierunku — a to dokładnie tam powstają słupki. Kratownica 3×3 okienek
(9 otworów, 12 słupków, 4 skrzyżowania nienaruszonej tkaniny) wynika z 6 elementów
<stx_cut> — trzech pionowych i trzech poziomych. Prostokątami otworów trzeba by
ją opisać 25 elementami i nadal nie dałoby się odróżnić słupka poziomego od pionowego.
7.3 stx_bar — słupek
<stx_bar x1="12" y1="18" x2="16" y2="18" kind="woven" threads="4" palindex="3" />
x1,y1 → x2,y2 to linia środkowa pasma nitek, które przetrwały cięcie,
nie bounding box. Takie pasma mają parzystą szerokość, więc linia środkowa zawsze wypada na
całkowitej współrzędnej. threads = ile nitek zostało (typowo 4).
kind ∈ wrapped | woven | divided | lacedBehind | twisted | zigzag |
overwrapped | buttonholed. overwrapped to słupek owinięty za gęsto na swoją
długość, przez co się wybrzusza (cztery takie wokół okienka czytają się jako okrąg);
buttonholed to słupek kryty ściegiem dziurkowym. Lista jest addytywna,
a jej kolejność zamrożona (bajt rodzaju jest kluczem sortowania i tagiem rekordu
w implementacjach — patrz §9.3); nowe rodzaje dochodzą na końcu.
kind odrzuca REKORD, nie plik. Czytnik
MUST NOT podmieniać jej na wrapped: słupek o nieznanej obróbce
narysowany jako owijany jest kłamstwem o robocie, a nie degradacją. Praktyczna konsekwencja: rodzaj
dodany przez nowszy writer jest dla starszego czytnika niewidoczny — ten jeden słupek wypada
z wykresu, reszta pliku wczytuje się normalnie.
Istnienie słupka jest wyliczalne (§9.1), ale kind to decyzja
autora wzoru i MUST być zapisane. Czytnik MUST NOT
zakładać wrapped przy braku elementu: brak oznacza, że autor nie określił słupka, a nie
że jest owijany.
7.4 stx_filling — wypełnienie okienka
<stx_filling x1="20" y1="20" x2="24" y2="24" catalog="doves-eye"
rot="0" mirror="0" palindex="3" weight="12">
<stx_path closed="1">22.00,20.00 22.51,20.43 … 22.00,20.00</stx_path>
</stx_filling>
x1..y2— okienko (obszar między słupkami i klostrami), w nitkach.catalog— id w katalogu wypełnień writera, trzymane do re-edycji. Czytnik MAY go nie znać.rot∈0|90|180|270,mirror∈0|1.weight— statyczna waga jednostki pracy (§10).<stx_path>— rozwiązana geometria: jedna lub wiele polilinii,x,yrozdzielone przecinkiem, punkty rozdzielone białym znakiem.closed="1"zamyka polilinię. Ułamki dozwolone.
<stx_path> jest normatywny, catalog jest podpowiedzią.
Renderer MUST rysować z <stx_path>. Writer
MUST go wygenerować dla każdego wypełnienia. To właśnie czyni prawdziwą
zasadę 3 z §1: plik nie może zacząć renderować się inaczej dlatego, że ktoś
zaktualizował katalog.
Parsowanie jest rygorystyczne, bo <stx_path> jest normatywny.
Jeden błędny token unieważnia całą polilinię — geometrii normatywnej nie wolno po cichu
przyciąć o punkt — a <stx_filling>, któremu nie została ani jedna poprawna
polilinia, odrzuca się w całości. Inaczej „rysuj z <stx_path>” zamienia się
w „rysuj z tego, co się sparsowało”. <stx_stitch> (§7.5) żyje
bez ścieżek: jego geometrię niesie katalog i span.
7.5 stx_stitch — ścieg powierzchniowy
<stx_stitch x="16" y="16" catalog="eyelet" span="4"
palindex="3" rot="0" weight="8" />
Ściegi zakotwiczone w punkcie lub kwadratowym obszarze, a nie w okienku między słupkami: oczko
algierskie, ścieg czterostronny. span = rozmiar w nitkach. Elementy o złożonej
geometrii MAY nieść dzieci <stx_path> na tych samych
zasadach co §7.4.
catalog MUST NOT być pusty — element opisuje ścieg
z katalogu. Ścieg bez wpisu w katalogu i bez kwadratowego śladu opisuje
§7.6.
7.6 stx_straight — ścieg pojedynczy
<stx_straight x1="12" y1="8" x2="19" y2="15" palindex="2" />
Jeden ścieg prosty położony na nieciętej tkaninie, opisany dwoma końcami (węzły, w nitkach). Żyje
w kolekcji <stx_surface> obok <stx_stitch>, ale jest osobnym
elementem, bo nie ma ani id katalogu, ani kwadratowego span — a
§7.5 wymaga obu.
To nie jest stx_satin z count="1".
stx_satin@axis przyjmuje wyłącznie h/v, więc ścieg na skos nie
ma tam jak zamieszkać bez zmiany znaczenia istniejącego atrybutu — a to byłoby zmianą łamiącą
(§12).
Kąt nie jest własnością formatu. Element niesie geometrię: dwa dowolne węzły.
Edytor może ograniczać gest do czterech kierunków; czytnik MUST przyjąć
każdą parę węzłów. x1,y1 MUST różnić się od x2,y2
— ścieg zerowej długości nie jest ściegiem.
7.7 stx_picot — picot
<stx_picots>
<stx_picot x="6" y="8" kind="knotted" dir="n" palindex="2" />
</stx_picots>
| Atrybut | Znaczenie |
|---|---|
x,y | Punkt zaczepu na hoście, w nitkach — ułamkowy. |
kind | knotted | looped | chain |
dir | n ne e se s sw w nw — kierunek wystawania glifu z hosta. |
palindex | Nić robocza. |
Picot to guzek doczepiony do istniejącej obróbki: środka słupka (wystaje w otwór), narożnika
wyciętego okienka (diagonalnie w otwór) albo boku wypełnienia. Dostaje własną kolekcję zamiast
atrybutu na <stx_bar>, bo hostem bywa wypełnienie — a parser strumieniowy i tak
nie wiąże dzieci z rodzicem.
Format nie niesie referencji do hosta. Tak jak kropki cięcia
(§9.2) są wyliczane, tak picot jest samodzielną geometrią: zaczep i kierunek
wystarczają do narysowania glifu, a wybór hosta jest regułą edytora, nie pliku. Czytnik
MUST przyjąć każdy legalny punkt — także taki, pod którym żadnej obróbki nie
ma. Nieznana wartość kind/dir odrzuca rekord, nie plik.
Picoty z koralikiem nie używają tego elementu — koralik jest innym materiałem i idzie do §7.8.
7.8 stx_bead — koralik w ażurze
<stx_beads>
<stx_bead x="22.0" y="20.0" palindex="6" />
</stx_beads>
Koralik będący częścią roboty hardanger — siedzący w narożniku wypełnienia albo na słupku jako picot z koralikiem. Pozycja jest w nitkach i ułamkowa, jak punkty ścieżek: przy okienku innym niż 4×4 nitki narożnik wypełnienia nie wypada na całkowitej nitce.
Ma własny element, a nie ścieżkę wypełnienia, bo koralik to inny materiał:
narysowanie go ściegiem okłamałoby każdego, kto liczy materiały — lista zakupów pokazałaby więcej
kordonka tam, gdzie potrzebna jest paczka koralików. Zwykłe koraliki wzoru, niezwiązane z ażurem,
zostają w standardowej sekcji <ornaments_inc_knots_and_beads>
(§1, zasada 2). Dlatego koralik nie ma weight
(§10) i nie wchodzi do <stx_threads>
(§6).
Element należy do powierzchni wersji 1 (§12), tak jak każdy inny rekord z §7.
8. Ściegi powierzchniowe a sekcje standardowe
Ścieg powierzchniowy hardanger MUST iść do <stx_surface>,
nigdy do <backstitches>, nawet gdy geometrycznie dałby się wyrazić liniami. Powód:
<backstitches> ma zdefiniowaną semantykę (ścieg konturowy) i własny render,
którego rozszerzenie MUST NOT zmieniać.
9. Semantyka wyliczana
Wszystko w tej sekcji MUST być wyliczane przez czytnik i MUST NOT być zapisywane w pliku.
9.1 Klasyfikacja regionów
Dla punktu (x,y): v = objęty pasmem dir="v",
h = objęty pasmem dir="h".
v | h | Region |
|---|---|---|
| ✓ | ✓ | Otwór — brak tkaniny w obu kierunkach. |
| ✓ | ✗ | Nitki poziome przetrwały → słupek poziomy. |
| ✗ | ✓ | Nitki pionowe przetrwały → słupek pionowy. |
| ✗ | ✗ | Nienaruszona tkanina. |
Granice regionów to krawędzie pasm <stx_cut>. Renderer i walidator używają tej
samej funkcji.
9.2 Pozycje kropek cięcia (styl wykresu)
Kropka oznacza miejsce przecięcia nitki — czoło pasma przy klostrze — a nie obwódkę otworu. Nitkę przecina się tylko tam, gdzie klostr ją zabezpiecza, a potem wyciąga na całej długości.
Dla pasma dir="v", x1..x2, y1..y2, o
n = x2 − x1 nitkach:
- kropki na
y = y1orazy = y2(dwa czoła), - w pozycjach
x = x1 + k + 0.5dlak = 0 … n−1.
Analogicznie dla dir="h". Otwory wewnętrzne kratownicy nie mają kropek
— tam nic nie przecinano. Reguła jest w całości wyliczalna z <stx_cut>; format nie
niesie kropek.
unsecuredEdge.9.3 Kolejność kanoniczna
Wyliczany z typu rekordu, nigdy zapisywany. Bajt jest jednocześnie tagiem typu i pierwszym kluczem sortowania, a kolejność jest zamrożona — czytnik śledzący postęp per rekord indeksuje po pozycji w tej posortowanej tablicy, więc przenumerowanie rozjechałoby cudzy postęp:
0. <stx_satin> (wszystkie role)
1. <stx_cut>
2. <stx_bar>
3. <stx_filling>
4. <stx_stitch> (kolekcja <stx_surface>)
5. <stx_bead>
6. <stx_straight> (ta sama KOLEKCJA co <stx_stitch>, osobny typ rekordu)
7. <stx_picot>
Wewnątrz typu rekordy sortują się po pełnej zapisanej treści, zaczynając od (y, x).
Sekcje standardowe OXS mają własne porządki i z tym nie interferują.
To porządek kanoniczny formatu, a nie kolejność haftowania. Ta idzie
z rzemiosła i wygląda inaczej: satyna i klostry → ściegi ciągnione → ściegi powierzchniowe →
krzyżyki i kontury → cięcie i wyciągnięcie nitek → słupki → wypełnienia → ozdoby.
Ściegi powierzchniowe — w tym <stx_straight>, który leży na całej tkaninie —
przypadają więc przed cięciem, a nie po nim. Autor MAY opisać własną
kolejność w standardowym properties/@instructions; format nie dodaje na nią pola.
10. Wagi jednostek pracy
weight to przybliżona liczba przewleczeń igły. Jest statyczna i
MUST być w pliku, żeby czytnik mógł policzyć postęp albo czas
bez katalogu wypełnień.
| Jednostka | weight |
|---|---|
| Pełny krzyżyk (dla odniesienia) | 1 |
Ścieg pojedynczy (stx_straight) | 1 |
Picot (stx_picot) | 1 |
| Klostr (5 ściegów) | 5 |
| Słupek owijany, 4 nitki | 8 |
| Słupek skręcany, 4 nitki | 8 |
| Linia zygzakowata, 4 nitki | 6 |
| Oczko algierskie 16-punktowe | 8 |
| Dove's eye | 12 |
| Square filet | 16 |
Koralik (stx_bead) | — liczony w sztukach, nie w przewleczeniach |
Wypełnienia katalogowe niosą własny atrybut weight na rekordzie, więc czytnik nigdy nie
potrzebuje tej tabeli dla typów spoza niej. Czytnik liczący procent postępu
SHOULD używać ważonej sumy; dla wzoru bez hardangeru wszystkie wagi = 1,
więc wynik jest bit-identyczny z liczeniem po sztukach.
11. Zgodność
Czytnik minimalny (bez wsparcia hardangeru)
- MUST pomijać nieznane elementy
stx_*bez błędu; - pokaże marker jak każdy inny komentarz — to zamierzony fallback: treść markera mówi użytkownikowi, że wzór wymaga wsparcia hardangeru;
- SHOULD ostrzec, gdy rozumie
<stx_extensions>, ale nieid="hardanger"zrequired="true".
Czytnik pełny
- MUST czytać
threadsperunit, a nie zakładać wartości; - MUST czytać koordy
stx_*jako 0-based, bez heurystyk przesunięcia (§2); - MUST wyliczać §9, a nie oczekiwać tych danych w pliku;
- MUST rysować wypełnienia z
<stx_path>, nie zcatalog; - MUST wykryć przypadek utraty danych z §4 (marker bez bloku) i ostrzec;
- MUST ukrywać marker przed użytkownikiem;
- MUST przepuścić każdy atrybut liczbowy przez JEDEN chokepoint domeny
i odrzucić rekord (nie plik i nie wartość po cichu podmienioną na inną), gdy
wartość jest poza domeną — wrogi plik nie może trapować ani brickować wzoru. Domeny: ułamki
skończone,
|v| < 1e9; współrzędne całkowite0…65 535;palindex0…65 534;count/span/threads/threadsperunit≥ 1;derived/mirror/closeddokładnie0albo1;rot0|90|180|270;weight0…1 000 000. Brak atrybutu wymaganego (np.derivedw<stx_cut>albocatalogw wypełnieniu i ściegu powierzchniowym) odrzuca rekord tak samo jak wartość spoza domeny; - MUST odrzucić rekord z nieznaną wartością enuma (
kind,dir,role,axis,weightnici) zamiast podmieniać ją na domyślną; - MUST wymagać
x1 < x2iy1 < y2tam, gdzie rekord jest prostokątem (<stx_cut>,<stx_filling>), orazx1,y1 ≠ x2,y2w<stx_straight>; - MUST NOT zmieniać renderu
<backstitches>.
Writer
- MUST wygenerować
<stx_extensions>przy niepustym bloku hardanger; - MUST wiązać
fallbacki marker z zapisywalnymi rekordami, a nie z samą obecnością bloku: blok niosący wyłącznie<stx_threads>albo niestandardowethreadsperunitniczego przed czytnikiem minimalnym nie ukrywa, więc idzie zfallback="none"i bez markera. Marker mówiący „0 kloster blocks…” wracałby po obcym round-tripie jako fałszywa utrata danych; - przy
fallback="comment": MUST wygenerować dokładnie jeden marker (§4) i MUST NOT emitować go, gdy blok nie niesie rekordów; - MUST wygenerować
<stx_path>dla każdego<stx_filling>i MUST pominąć w eksporcie wypełnienie bez rozwiązanej geometrii, zamiast zapisywać je bez ścieżki; - MUST NOT zapisywać danych z §9;
- MUST NOT dodawać atrybutów do standardowych elementów OXS.
12. Polityka wersjonowania
stx_extensions/@version— wersja mechanizmu rozszerzeń. Zmiana = zmiana łamiąca.stx_feature/@version— wersja definicji rodziny. Nowe opcjonalne atrybuty i nowe wartości enumów podnoszą ją i MUST być pomijalne przez czytnik wersji 1.- Nowe rodziny technik MUST iść jako nowy
<stx_feature id="…">plus nowy blok top-level, nigdy przez rozciąganie<stx_hardanger>. - Usunięcie istniejącego atrybutu albo zmiana jego znaczenia MUST podnieść
stx_extensions/@version.
Rodzina hardanger w wersji 1 to CAŁA powierzchnia opisana w
§5–§9: satyny, pasma cięcia, słupki z ośmioma
rodzajami, wypełnienia, ściegi powierzchniowe, koraliki, ściegi pojedyncze i picoty. Plik zgodny
z tym dokumentem MUST deklarować version="1" niezależnie od
tego, które z tych rekordów niesie.
Mechanizm adaptacyjny włącza się przy pierwszym dodatku po publikacji. Od tego
momentu stx_feature/@version MUST być najwyższą wersją, której
plik faktycznie wymaga, a nie najwyższą, którą writer umie: plik bez rekordów z wersji 2
MUST nadal deklarować 1, bo przy required="true"
stałe 2 kazałoby ostrożnemu czytnikowi wersji 1 odrzucić wzór, który poza tym jest
w całości wersji 1 — czyli plik, który otwierał dzień wcześniej. Czytnik trzyma najwyższą
obsługiwaną wersję rodziny i plik deklarujący więcej raportuje jako nieobsługiwany, zamiast rysować
go po cichu niepełnie.
13. Poza zakresem wersji 1
- Jedwabna wstążka (lazy daisy, spider web rose, french knots) — realna
i występuje w tych samych wzorach co hardanger, ale to osobna rodzina:
<stx_feature id="silkribbon">w przyszłej wersji. Architektura §3 to przewiduje. - Inne techniki drawn-thread (Schwalm, reticello, hemstitch) — osobne
id. - Instrukcje tekstowe i warianty dla lewo-/praworęcznych — to nie treść formatu.
- Sam katalog wypełnień — format niesie id
catalogi rozwiązaną ścieżkę; katalog jest artefaktem implementacji, nie częścią formatu. - Import z formatów zamkniętych — tamtejsze bloby „special stitches” są nieudokumentowane i nie da się ich odwzorować wiarygodnie.
14. Plik referencyjny
Prawdziwy wzór wyeksportowany ze StitchTracker Studio, nie ręcznie pisana próbka: 27×27 komórek, dwa medaliony, 32 klostry, 12 pasm cięcia, 12 słupków i 6 wypełnień (maltese flower i twisted Y, każde z rozwiązaną, wielopolilinijną geometrią), a do tego 264 kontury, 3 pełne krzyżyki i 5 koralików w sekcjach standardowych. Otwarty w czytniku bez wsparcia hardangeru pokaże krzyżykowy szkielet, kontury i marker-komentarz; w czytniku pełnym — cały ażur.
Dzisiejsze implementacje: StitchTracker (czytnik, iPadOS/iOS) i StitchTracker Studio (writer). Jeśli implementujesz to rozszerzenie u siebie i coś tu jest niejednoznaczne albo potrzebujesz wektora testowego na przypadek, którego plik referencyjny nie pokrywa — napisz na krzysiekobateam@gmail.com. Poprawki do tego dokumentu są mile widziane.