From 3feb8fe94f54cd7521a72fef04c33e44835ec9af Mon Sep 17 00:00:00 2001 From: Maurice Date: Sat, 24 Oct 2026 09:29:33 +0200 Subject: [PATCH] feat(studio): linen and paper grain, two quiet textures among the patterns --- .../src/components/Studio/paint/patterns.ts | 49 ++++++++++++++++--- shared/src/book/book-paint.schema.ts | 2 + shared/src/book/book-paint.spec.ts | 2 +- shared/src/book/data/book-asset-lines.data.ts | 2 + shared/src/i18n/ar/studioPaint.ts | 2 + shared/src/i18n/az/studioPaint.ts | 2 + shared/src/i18n/br/studioPaint.ts | 2 + shared/src/i18n/ca/studioPaint.ts | 2 + shared/src/i18n/cs/studioPaint.ts | 2 + shared/src/i18n/de/studioPaint.ts | 2 + shared/src/i18n/en/studioPaint.ts | 2 + shared/src/i18n/es/studioPaint.ts | 2 + shared/src/i18n/et/studioPaint.ts | 2 + shared/src/i18n/fr/studioPaint.ts | 2 + shared/src/i18n/gr/studioPaint.ts | 2 + shared/src/i18n/hu/studioPaint.ts | 2 + shared/src/i18n/id/studioPaint.ts | 2 + shared/src/i18n/it/studioPaint.ts | 2 + shared/src/i18n/ja/studioPaint.ts | 2 + shared/src/i18n/ko/studioPaint.ts | 2 + shared/src/i18n/nl/studioPaint.ts | 2 + shared/src/i18n/pl/studioPaint.ts | 2 + shared/src/i18n/ru/studioPaint.ts | 2 + shared/src/i18n/sk/studioPaint.ts | 2 + shared/src/i18n/sv/studioPaint.ts | 2 + shared/src/i18n/th/studioPaint.ts | 2 + shared/src/i18n/tr/studioPaint.ts | 2 + shared/src/i18n/uk/studioPaint.ts | 2 + shared/src/i18n/vi/studioPaint.ts | 2 + shared/src/i18n/zh-TW/studioPaint.ts | 2 + shared/src/i18n/zh/studioPaint.ts | 2 + 31 files changed, 100 insertions(+), 9 deletions(-) diff --git a/client/src/components/Studio/paint/patterns.ts b/client/src/components/Studio/paint/patterns.ts index 65944e101..0b13329bd 100644 --- a/client/src/components/Studio/paint/patterns.ts +++ b/client/src/components/Studio/paint/patterns.ts @@ -46,6 +46,11 @@ interface PatternGeometry { const r2 = (v: number) => Math.round(v * 100) / 100 || 0; const f = (v: number) => String(r2(v)); +/** Threads per cell each way in linen: fine enough to read as cloth, few enough for a whole page under the cap. */ +const LINEN_THREADS = 6; +/** Specks per cell in grain. */ +const GRAIN_SPECKS = 3; + /** * How many primitives a repeat needs over a region: `area` primitives per * cell squared, `lin` per cell along the width and the height. Read before @@ -66,6 +71,8 @@ const DENSITY: Record = { scales: { area: 2, lin: 0 }, sunburst: { area: 0, lin: 0 }, confetti: { area: 1.2, lin: 0 }, + linen: { area: 0, lin: 2 * LINEN_THREADS }, + grain: { area: GRAIN_SPECKS, lin: 0 }, }; /** A primitive count estimate for a repeat over a region at a cell size. */ @@ -269,6 +276,24 @@ const DRAW: Record, Draw> = { ]); } }, + // Threads of uneven weight both ways, on two half-clear layers: where they cross the cloth reads denser. + linen: (pen, g, s, alt) => { + const rand = mulberry32(Math.round(s * 1000) + 31); + const pitch = s / LINEN_THREADS; + for (const y of steps(g.y0, g.y1, pitch)) pen.rect(g.x0, y, g.x1 - g.x0, pitch * (0.2 + rand() * 0.35)); + for (const x of steps(g.x0, g.x1, pitch)) alt.rect(x, g.y0, pitch * (0.2 + rand() * 0.35), g.y1 - g.y0); + }, + // Specks of a few sizes, the larger ones fainter, scattered the same way on every render. + grain: (pen, g, s, alt) => { + const rand = mulberry32(Math.round(s * 1000) + 43); + const n = Math.round((((g.x1 - g.x0) * (g.y1 - g.y0)) / (s * s)) * GRAIN_SPECKS); + for (let i = 0; i < n && !pen.full && !alt.full; i++) { + const x = g.x0 + rand() * (g.x1 - g.x0); + const y = g.y0 + rand() * (g.y1 - g.y0); + if (rand() < 0.6) pen.circle(x, y, s * (0.012 + rand() * 0.012)); + else alt.circle(x, y, s * (0.025 + rand() * 0.02)); + } + }, }; /** A seeded generator, so a confetti page draws the same scatter on every render and in print. */ @@ -307,6 +332,13 @@ function sunburst(pen: Pen, box: PatternBox, cell: number, angle: number) { } } +/** The repeats drawn on two layers, and how clear each layer is: textures stay quiet over their ground. */ +const LAYER_OPACITY: Partial> = { + gingham: [0.5, 0.5], + linen: [0.32, 0.32], + grain: [0.5, 0.28], +}; + /** * A repeat over a box. The geometry covers the box however it is turned: the * region drawn is the square around the box's circumscribed circle, and the @@ -338,17 +370,18 @@ export function patternGeometry( return { layers: [{ d: pen.d, opacity: 1 }], count: pen.count, cell }; } - // The second layer only ever holds gingham's cross bands; the cell fitted above keeps both under the cap together. + // The second layer holds gingham's and linen's cross bands and grain's larger specks; + // the cell fitted above keeps both under the cap together. const alt = new Pen(cap); DRAW[paint.pattern](pen, region, cell, alt); const count = pen.count + alt.count; - const layers = - paint.pattern === 'gingham' - ? [ - { d: pen.d, opacity: 0.5 }, - { d: alt.d, opacity: 0.5 }, - ] - : [{ d: pen.d, opacity: 1 }]; + const two = LAYER_OPACITY[paint.pattern]; + const layers = two + ? [ + { d: pen.d, opacity: two[0] }, + { d: alt.d, opacity: two[1] }, + ] + : [{ d: pen.d, opacity: 1 }]; return { layers: layers.filter((l) => l.d), count, diff --git a/shared/src/book/book-paint.schema.ts b/shared/src/book/book-paint.schema.ts index 601475b09..e4ed4a87b 100644 --- a/shared/src/book/book-paint.schema.ts +++ b/shared/src/book/book-paint.schema.ts @@ -42,6 +42,8 @@ export const BOOK_PATTERNS = [ 'scales', 'sunburst', 'confetti', + 'linen', + 'grain', ] as const; export type BookPattern = (typeof BOOK_PATTERNS)[number]; diff --git a/shared/src/book/book-paint.spec.ts b/shared/src/book/book-paint.spec.ts index 8b32d57de..8b88a61f9 100644 --- a/shared/src/book/book-paint.spec.ts +++ b/shared/src/book/book-paint.spec.ts @@ -71,7 +71,7 @@ describe('the paint contract', () => { for (const p of [{ type: 'solid', color: '#abcdef', alpha: 0.4 }, linear, radial, stripes]) { expect(bookPaintSchema.parse(p)).toEqual(p); } - expect(BOOK_PATTERNS).toHaveLength(12); + expect(BOOK_PATTERNS).toHaveLength(14); for (const pattern of BOOK_PATTERNS) expect(bookPaintSchema.safeParse({ ...stripes, pattern }).success).toBe(true); }); diff --git a/shared/src/book/data/book-asset-lines.data.ts b/shared/src/book/data/book-asset-lines.data.ts index 6345840ea..dd33f0728 100644 --- a/shared/src/book/data/book-asset-lines.data.ts +++ b/shared/src/book/data/book-asset-lines.data.ts @@ -138,4 +138,6 @@ export const BOOK_PATTERN_LINES: Readonly> = { scales: 'Overlapping half circles, fish scales or roof tiles.', sunburst: 'Rays from a centre, a sunburst.', confetti: 'Scattered confetti.', + linen: 'Fine woven threads, the texture of a cloth-bound book, best in a colour close to its ground.', + grain: 'Fine scattered specks, the grain of paper or kraft card, best in a colour close to its ground.', }; diff --git a/shared/src/i18n/ar/studioPaint.ts b/shared/src/i18n/ar/studioPaint.ts index a4c3a8307..7e8f2c296 100644 --- a/shared/src/i18n/ar/studioPaint.ts +++ b/shared/src/i18n/ar/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'حراشف', 'journey.studio.pattern.sunburst': 'أشعة الشمس', 'journey.studio.pattern.confetti': 'قصاصات ملونة', + 'journey.studio.pattern.linen': 'كتان', + 'journey.studio.pattern.grain': 'حبيبات الورق', }; export default studioPaint; diff --git a/shared/src/i18n/az/studioPaint.ts b/shared/src/i18n/az/studioPaint.ts index 2fa2c750a..d92214894 100644 --- a/shared/src/i18n/az/studioPaint.ts +++ b/shared/src/i18n/az/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Pulcuqlar', 'journey.studio.pattern.sunburst': 'Şüalar', 'journey.studio.pattern.confetti': 'Konfeti', + 'journey.studio.pattern.linen': 'Kətan', + 'journey.studio.pattern.grain': 'Kağız dənəsi', }; export default studioPaint; diff --git a/shared/src/i18n/br/studioPaint.ts b/shared/src/i18n/br/studioPaint.ts index b22a45892..123092017 100644 --- a/shared/src/i18n/br/studioPaint.ts +++ b/shared/src/i18n/br/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Escamas', 'journey.studio.pattern.sunburst': 'Raios de sol', 'journey.studio.pattern.confetti': 'Confete', + 'journey.studio.pattern.linen': 'Linho', + 'journey.studio.pattern.grain': 'Textura de papel', }; export default studioPaint; diff --git a/shared/src/i18n/ca/studioPaint.ts b/shared/src/i18n/ca/studioPaint.ts index 8ab2d756e..d871f7eaa 100644 --- a/shared/src/i18n/ca/studioPaint.ts +++ b/shared/src/i18n/ca/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Escates', 'journey.studio.pattern.sunburst': 'Raigs', 'journey.studio.pattern.confetti': 'Confeti', + 'journey.studio.pattern.linen': 'Lli', + 'journey.studio.pattern.grain': 'Gra de paper', }; export default studioPaint; diff --git a/shared/src/i18n/cs/studioPaint.ts b/shared/src/i18n/cs/studioPaint.ts index 0532d69a4..0b01104e6 100644 --- a/shared/src/i18n/cs/studioPaint.ts +++ b/shared/src/i18n/cs/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Šupiny', 'journey.studio.pattern.sunburst': 'Paprsky', 'journey.studio.pattern.confetti': 'Konfety', + 'journey.studio.pattern.linen': 'Plátno', + 'journey.studio.pattern.grain': 'Zrno papíru', }; export default studioPaint; diff --git a/shared/src/i18n/de/studioPaint.ts b/shared/src/i18n/de/studioPaint.ts index 9aa444bca..cfbebc9b8 100644 --- a/shared/src/i18n/de/studioPaint.ts +++ b/shared/src/i18n/de/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Schuppen', 'journey.studio.pattern.sunburst': 'Strahlen', 'journey.studio.pattern.confetti': 'Konfetti', + 'journey.studio.pattern.linen': 'Leinen', + 'journey.studio.pattern.grain': 'Papierkorn', }; export default studioPaint; diff --git a/shared/src/i18n/en/studioPaint.ts b/shared/src/i18n/en/studioPaint.ts index be0e8c268..1ea16482e 100644 --- a/shared/src/i18n/en/studioPaint.ts +++ b/shared/src/i18n/en/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Scales', 'journey.studio.pattern.sunburst': 'Sunburst', 'journey.studio.pattern.confetti': 'Confetti', + 'journey.studio.pattern.linen': 'Linen', + 'journey.studio.pattern.grain': 'Paper grain', }; export default studioPaint; diff --git a/shared/src/i18n/es/studioPaint.ts b/shared/src/i18n/es/studioPaint.ts index 2523cb4ab..1cd6f84a6 100644 --- a/shared/src/i18n/es/studioPaint.ts +++ b/shared/src/i18n/es/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Escamas', 'journey.studio.pattern.sunburst': 'Rayos', 'journey.studio.pattern.confetti': 'Confeti', + 'journey.studio.pattern.linen': 'Lino', + 'journey.studio.pattern.grain': 'Grano de papel', }; export default studioPaint; diff --git a/shared/src/i18n/et/studioPaint.ts b/shared/src/i18n/et/studioPaint.ts index 39d6b7571..820c1c1bc 100644 --- a/shared/src/i18n/et/studioPaint.ts +++ b/shared/src/i18n/et/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Soomused', 'journey.studio.pattern.sunburst': 'Päikesekiired', 'journey.studio.pattern.confetti': 'Konfetid', + 'journey.studio.pattern.linen': 'Linane', + 'journey.studio.pattern.grain': 'Paberi tekstuur', }; export default studioPaint; diff --git a/shared/src/i18n/fr/studioPaint.ts b/shared/src/i18n/fr/studioPaint.ts index 288e2d21d..8251f1c5f 100644 --- a/shared/src/i18n/fr/studioPaint.ts +++ b/shared/src/i18n/fr/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Écailles', 'journey.studio.pattern.sunburst': 'Rayons', 'journey.studio.pattern.confetti': 'Confettis', + 'journey.studio.pattern.linen': 'Lin', + 'journey.studio.pattern.grain': 'Grain de papier', }; export default studioPaint; diff --git a/shared/src/i18n/gr/studioPaint.ts b/shared/src/i18n/gr/studioPaint.ts index 1e6608868..e4b02acc5 100644 --- a/shared/src/i18n/gr/studioPaint.ts +++ b/shared/src/i18n/gr/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Λέπια', 'journey.studio.pattern.sunburst': 'Ηλιαχτίδες', 'journey.studio.pattern.confetti': 'Κομφετί', + 'journey.studio.pattern.linen': 'Λινό', + 'journey.studio.pattern.grain': 'Υφή χαρτιού', }; export default studioPaint; diff --git a/shared/src/i18n/hu/studioPaint.ts b/shared/src/i18n/hu/studioPaint.ts index fe5fe73c6..55225db92 100644 --- a/shared/src/i18n/hu/studioPaint.ts +++ b/shared/src/i18n/hu/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Pikkelyek', 'journey.studio.pattern.sunburst': 'Sugarak', 'journey.studio.pattern.confetti': 'Konfetti', + 'journey.studio.pattern.linen': 'Vászon', + 'journey.studio.pattern.grain': 'Papírszemcse', }; export default studioPaint; diff --git a/shared/src/i18n/id/studioPaint.ts b/shared/src/i18n/id/studioPaint.ts index 2b49f7421..c897609b0 100644 --- a/shared/src/i18n/id/studioPaint.ts +++ b/shared/src/i18n/id/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Sisik', 'journey.studio.pattern.sunburst': 'Sinar matahari', 'journey.studio.pattern.confetti': 'Konfeti', + 'journey.studio.pattern.linen': 'Linen', // same-as-en + 'journey.studio.pattern.grain': 'Tekstur kertas', }; export default studioPaint; diff --git a/shared/src/i18n/it/studioPaint.ts b/shared/src/i18n/it/studioPaint.ts index 98aa11ea6..8946f1d95 100644 --- a/shared/src/i18n/it/studioPaint.ts +++ b/shared/src/i18n/it/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Squame', 'journey.studio.pattern.sunburst': 'Raggiera', 'journey.studio.pattern.confetti': 'Coriandoli', + 'journey.studio.pattern.linen': 'Lino', + 'journey.studio.pattern.grain': 'Grana della carta', }; export default studioPaint; diff --git a/shared/src/i18n/ja/studioPaint.ts b/shared/src/i18n/ja/studioPaint.ts index f736ffcad..62e72b236 100644 --- a/shared/src/i18n/ja/studioPaint.ts +++ b/shared/src/i18n/ja/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'うろこ', 'journey.studio.pattern.sunburst': 'サンバースト', 'journey.studio.pattern.confetti': '紙吹雪', + 'journey.studio.pattern.linen': 'リネン', + 'journey.studio.pattern.grain': '紙の質感', }; export default studioPaint; diff --git a/shared/src/i18n/ko/studioPaint.ts b/shared/src/i18n/ko/studioPaint.ts index b27426512..0590f84fa 100644 --- a/shared/src/i18n/ko/studioPaint.ts +++ b/shared/src/i18n/ko/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': '비늘', 'journey.studio.pattern.sunburst': '햇살', 'journey.studio.pattern.confetti': '색종이 조각', + 'journey.studio.pattern.linen': '리넨', + 'journey.studio.pattern.grain': '종이 질감', }; export default studioPaint; diff --git a/shared/src/i18n/nl/studioPaint.ts b/shared/src/i18n/nl/studioPaint.ts index 1b176b23a..2a8ba10ec 100644 --- a/shared/src/i18n/nl/studioPaint.ts +++ b/shared/src/i18n/nl/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Schubben', 'journey.studio.pattern.sunburst': 'Zonnestralen', 'journey.studio.pattern.confetti': 'Confetti', // same-as-en + 'journey.studio.pattern.linen': 'Linnen', + 'journey.studio.pattern.grain': 'Papierkorrel', }; export default studioPaint; diff --git a/shared/src/i18n/pl/studioPaint.ts b/shared/src/i18n/pl/studioPaint.ts index 3fe9aa359..24433b6d6 100644 --- a/shared/src/i18n/pl/studioPaint.ts +++ b/shared/src/i18n/pl/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Łuski', 'journey.studio.pattern.sunburst': 'Promienie', 'journey.studio.pattern.confetti': 'Konfetti', + 'journey.studio.pattern.linen': 'Len', + 'journey.studio.pattern.grain': 'Faktura papieru', }; export default studioPaint; diff --git a/shared/src/i18n/ru/studioPaint.ts b/shared/src/i18n/ru/studioPaint.ts index e1ff683b6..65fcc6b12 100644 --- a/shared/src/i18n/ru/studioPaint.ts +++ b/shared/src/i18n/ru/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Чешуя', 'journey.studio.pattern.sunburst': 'Солнечные лучи', 'journey.studio.pattern.confetti': 'Конфетти', + 'journey.studio.pattern.linen': 'Лён', + 'journey.studio.pattern.grain': 'Зерно бумаги', }; export default studioPaint; diff --git a/shared/src/i18n/sk/studioPaint.ts b/shared/src/i18n/sk/studioPaint.ts index da1cfb93e..cd7cddc55 100644 --- a/shared/src/i18n/sk/studioPaint.ts +++ b/shared/src/i18n/sk/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Šupiny', 'journey.studio.pattern.sunburst': 'Lúče', 'journey.studio.pattern.confetti': 'Konfety', + 'journey.studio.pattern.linen': 'Plátno', + 'journey.studio.pattern.grain': 'Zrno papiera', }; export default studioPaint; diff --git a/shared/src/i18n/sv/studioPaint.ts b/shared/src/i18n/sv/studioPaint.ts index 6b5e21a8c..d0e26d081 100644 --- a/shared/src/i18n/sv/studioPaint.ts +++ b/shared/src/i18n/sv/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Fjäll', 'journey.studio.pattern.sunburst': 'Solstrålar', 'journey.studio.pattern.confetti': 'Konfetti', + 'journey.studio.pattern.linen': 'Linne', + 'journey.studio.pattern.grain': 'Pappersstruktur', }; export default studioPaint; diff --git a/shared/src/i18n/th/studioPaint.ts b/shared/src/i18n/th/studioPaint.ts index 9fdbcbc0e..f4d2fa8c1 100644 --- a/shared/src/i18n/th/studioPaint.ts +++ b/shared/src/i18n/th/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'เกล็ด', 'journey.studio.pattern.sunburst': 'รัศมีแสง', 'journey.studio.pattern.confetti': 'กระดาษสี', + 'journey.studio.pattern.linen': 'ผ้าลินิน', + 'journey.studio.pattern.grain': 'เนื้อกระดาษ', }; export default studioPaint; diff --git a/shared/src/i18n/tr/studioPaint.ts b/shared/src/i18n/tr/studioPaint.ts index 39d50ac75..82b4e7a60 100644 --- a/shared/src/i18n/tr/studioPaint.ts +++ b/shared/src/i18n/tr/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Pullar', 'journey.studio.pattern.sunburst': 'Güneş ışınları', 'journey.studio.pattern.confetti': 'Konfeti', + 'journey.studio.pattern.linen': 'Keten', + 'journey.studio.pattern.grain': 'Kâğıt dokusu', }; export default studioPaint; diff --git a/shared/src/i18n/uk/studioPaint.ts b/shared/src/i18n/uk/studioPaint.ts index 2d95426a8..8a70520be 100644 --- a/shared/src/i18n/uk/studioPaint.ts +++ b/shared/src/i18n/uk/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Луска', 'journey.studio.pattern.sunburst': 'Сонячні промені', 'journey.studio.pattern.confetti': 'Конфеті', + 'journey.studio.pattern.linen': 'Льон', + 'journey.studio.pattern.grain': 'Зерно паперу', }; export default studioPaint; diff --git a/shared/src/i18n/vi/studioPaint.ts b/shared/src/i18n/vi/studioPaint.ts index 67e1c4135..ce857d613 100644 --- a/shared/src/i18n/vi/studioPaint.ts +++ b/shared/src/i18n/vi/studioPaint.ts @@ -45,5 +45,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': 'Vảy', 'journey.studio.pattern.sunburst': 'Tia nắng', 'journey.studio.pattern.confetti': 'Hoa giấy', + 'journey.studio.pattern.linen': 'Vải lanh', + 'journey.studio.pattern.grain': 'Vân giấy', }; export default studioPaint; diff --git a/shared/src/i18n/zh-TW/studioPaint.ts b/shared/src/i18n/zh-TW/studioPaint.ts index 546780184..f0d3d7aac 100644 --- a/shared/src/i18n/zh-TW/studioPaint.ts +++ b/shared/src/i18n/zh-TW/studioPaint.ts @@ -44,5 +44,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': '鱗片', 'journey.studio.pattern.sunburst': '放射光芒', 'journey.studio.pattern.confetti': '彩色紙花', + 'journey.studio.pattern.linen': '亞麻', + 'journey.studio.pattern.grain': '紙張紋理', }; export default studioPaint; diff --git a/shared/src/i18n/zh/studioPaint.ts b/shared/src/i18n/zh/studioPaint.ts index 1a4f2e26c..a191ecbb8 100644 --- a/shared/src/i18n/zh/studioPaint.ts +++ b/shared/src/i18n/zh/studioPaint.ts @@ -44,5 +44,7 @@ const studioPaint: TranslationStrings = { 'journey.studio.pattern.scales': '鳞片', 'journey.studio.pattern.sunburst': '放射光', 'journey.studio.pattern.confetti': '彩纸屑', + 'journey.studio.pattern.linen': '亚麻', + 'journey.studio.pattern.grain': '纸张纹理', }; export default studioPaint;