From 510fd40d86a14928dff8b20a9bdcb5628be27875 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 04:04:51 +0000 Subject: [PATCH] Rework the Wallace tartan from a reference, and set it on the bias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old sett was three flat stripes in roughly equal measure, which read as a generic red-and-black check rather than as Wallace. Rebuilt against a reference swatch. - Setts are now written as a half-sett and reflected about their pivots, the way a threadcount is actually published, so the data stays in the form it is quoted in instead of a flat list kept symmetric by hand. - Wallace is gold 6, black 6, red 36, black 24, red 36, black 6: a red ground at about two thirds, black bands alternating wide and narrow, and one thin gold overstripe per repeat. The reflection puts black on both sides of the gold line, which is what the reference shows. - Colours taken from the swatch: a brighter scarlet and a stronger gold than before. - Both the cloth and the icon are turned 45 degrees. The renderer draws well past the canvas edges so the corners stay covered once rotated. The icon vector is generated from the same numbers rather than written out by hand, so the icon and the splash cannot drift apart — changing the sett rebrands both. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN --- README.md | 22 ++-- .../org/prolibertate/games/ui/SplashScreen.kt | 2 + .../org/prolibertate/games/ui/theme/Tartan.kt | 122 +++++++++++------- .../res/drawable/ic_launcher_background.xml | 102 ++++++++------- app/src/main/res/mipmap/ic_launcher.xml | 76 ++++++++--- app/src/main/res/mipmap/ic_launcher_round.xml | 76 ++++++++--- 6 files changed, 266 insertions(+), 134 deletions(-) diff --git a/README.md b/README.md index 85c053d..fa0ea67 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ or against other people over Wi-Fi (LAN) or Bluetooth. ## What works today -The app shell is complete and two games are playable end to end: +The app shell is complete and four games are playable end to end: | | | | --- | --- | @@ -59,9 +59,9 @@ them. ## Branding -The launcher icon is a single square of the Wallace tartan, and the app opens on -a tartan splash carrying the name in a Celtic uncial hand for two seconds before -fading into the menu. +The launcher icon is a single square of the Wallace tartan set on the bias, and +the app opens on the same cloth carrying the name in a Celtic uncial hand for two +seconds before fading into the menu. The tartan is drawn, not an image: `ui/theme/Tartan.kt` lays the sett down as warp and then as weft at half opacity, which is what produces the blended @@ -70,12 +70,14 @@ drawable, so it stays sharp at every density and needs no PNGs. Two honest caveats: -- **The sett is an approximation.** `WallaceSett` reproduces what the Wallace - tartan reads as — a bold red and black check divided by a narrow gold - overstripe — but the registered threadcount could not be verified, so the - numbers were chosen to look right rather than to be authoritative. They are - plain data; replacing them with the registered counts rebrands the whole app - and needs no other change. +- **The sett is matched by eye, not to a registered threadcount.** + `WallaceSett` is written as a half-sett and reflected about its pivots, the way + a threadcount is published: gold 6, black 6, red 36, black 24, red 36, black 6. + That gives a red ground at about two thirds, black bands alternating wide and + narrow, and one thin gold overstripe per repeat flanked by black — matched + against a reference swatch rather than to the Scottish Register of Tartans. + Substituting registered counts is an edit to that one list; the icon is + generated from the same numbers, so both follow. - **The typeface is bundled under a licence.** Uncial Antiqua, © 2011 Brian J. Bonislawsky DBA Astigmatic, Reserved Font Name "Uncial Antiqua", used under the SIL Open Font License 1.1. The full licence is at diff --git a/app/src/main/java/org/prolibertate/games/ui/SplashScreen.kt b/app/src/main/java/org/prolibertate/games/ui/SplashScreen.kt index 4edff5c..e3f1ce8 100644 --- a/app/src/main/java/org/prolibertate/games/ui/SplashScreen.kt +++ b/app/src/main/java/org/prolibertate/games/ui/SplashScreen.kt @@ -82,6 +82,8 @@ fun SplashScreen( TartanBackground( modifier = Modifier.fillMaxSize(), threadWidth = threadWidth, + // On the bias, matching the icon. + rotationDegrees = 45f, ) // A scrim keeps the lettering legible over the busiest part of the sett. diff --git a/app/src/main/java/org/prolibertate/games/ui/theme/Tartan.kt b/app/src/main/java/org/prolibertate/games/ui/theme/Tartan.kt index a5024ad..4b64261 100644 --- a/app/src/main/java/org/prolibertate/games/ui/theme/Tartan.kt +++ b/app/src/main/java/org/prolibertate/games/ui/theme/Tartan.kt @@ -7,77 +7,106 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.rotate import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp /** One band of a tartan sett, measured in threads. */ data class TartanStripe(val color: Color, val threads: Int) -val WallaceRed = Color(0xFFB3121B) -val WallaceBlack = Color(0xFF111111) -val WallaceGold = Color(0xFFF2C200) +val WallaceRed = Color(0xFFE01B24) +val WallaceBlack = Color(0xFF0C0C0C) +val WallaceGold = Color(0xFFF2C518) /** - * The Wallace sett. + * Expands a half-sett into a full repeat by reflecting it. * - * NOTE: this is an approximation, not a certified threadcount. It reproduces - * what the Wallace tartan reads as — a bold red and black check divided by a - * narrow gold overstripe — but the exact thread counts held by the Scottish - * Register of Tartans could not be verified from here, so the numbers below - * are chosen to look right rather than to be authoritative. They are plain - * data: replacing them with the registered counts changes the whole app's - * branding and needs no other edit. + * Tartans are specified as a half-sett between two pivots and woven out to + * both sides, so `A B C` becomes `A B C B` — the pivot stripes are not + * doubled. Writing the data this way keeps it in the same form a threadcount + * is published in, instead of a flat list that has to be kept symmetric by + * hand. + */ +fun List.pivoted(): List = + if (size < 3) this else this + drop(1).dropLast(1).reversed() + +/** + * The Wallace sett, as a half-sett between the gold line and the centre of a + * narrow black guard. + * + * Matched by eye to a reference swatch rather than to a registered + * threadcount: red ground, black bands alternating wide and narrow, and one + * thin gold overstripe per repeat, flanked by black on both sides. The + * proportions are the point — swapping in registered counts is an edit to this + * list and nothing else. */ val WallaceSett: List = listOf( - TartanStripe(WallaceRed, 40), - TartanStripe(WallaceBlack, 40), - TartanStripe(WallaceGold, 4), -) + TartanStripe(WallaceGold, 6), + TartanStripe(WallaceBlack, 6), + TartanStripe(WallaceRed, 36), + TartanStripe(WallaceBlack, 24), + TartanStripe(WallaceRed, 36), + TartanStripe(WallaceBlack, 6), +).pivoted() /** * Draws a tartan by laying the sett down vertically as warp, then across as * weft at half opacity. The overlap is what produces the blended squares and * the sense of a woven cloth rather than a printed grid — red warp under black * weft comes out a darker red, exactly as it does on the loom. + * + * [rotationDegrees] turns the cloth on the bias. The stripes are drawn well + * past the edges of the canvas so the corners stay covered once it is turned. */ fun DrawScope.drawTartan( sett: List = WallaceSett, threadSize: Float, + rotationDegrees: Float = 0f, ) { if (sett.isEmpty() || threadSize <= 0f) return val repeat = sett.sumOf { it.threads } * threadSize if (repeat <= 0f) return - // Warp: full-height bands. - var x = 0f - while (x < size.width) { - var offset = x - for (stripe in sett) { - val width = stripe.threads * threadSize - drawRect( - color = stripe.color, - topLeft = Offset(offset, 0f), - size = Size(width, size.height), - ) - offset += width - } - x += repeat - } + // Turning a square by 45 degrees needs about 0.21 of its size spare on + // every edge; three quarters is generous enough for any angle. + val pad = if (rotationDegrees == 0f) 0f else size.maxDimension * 0.75f + val left = -pad + val top = -pad + val right = size.width + pad + val bottom = size.height + pad - // Weft: full-width bands, half opacity so the warp shows through. - var y = 0f - while (y < size.height) { - var offset = y - for (stripe in sett) { - val height = stripe.threads * threadSize - drawRect( - color = stripe.color.copy(alpha = 0.5f), - topLeft = Offset(0f, offset), - size = Size(size.width, height), - ) - offset += height + rotate(degrees = rotationDegrees) { + // Warp: full-height bands. + var x = left - (left.mod(repeat)) + while (x < right) { + var offset = x + for (stripe in sett) { + val width = stripe.threads * threadSize + drawRect( + color = stripe.color, + topLeft = Offset(offset, top), + size = Size(width, bottom - top), + ) + offset += width + } + x += repeat + } + + // Weft: full-width bands, half opacity so the warp shows through. + var y = top - (top.mod(repeat)) + while (y < bottom) { + var offset = y + for (stripe in sett) { + val height = stripe.threads * threadSize + drawRect( + color = stripe.color.copy(alpha = 0.5f), + topLeft = Offset(left, offset), + size = Size(right - left, height), + ) + offset += height + } + y += repeat } - y += repeat } } @@ -90,8 +119,13 @@ fun TartanBackground( modifier: Modifier = Modifier, sett: List = WallaceSett, threadWidth: Dp = 2.dp, + rotationDegrees: Float = 0f, ) { Canvas(modifier = modifier) { - drawTartan(sett = sett, threadSize = threadWidth.toPx()) + drawTartan( + sett = sett, + threadSize = threadWidth.toPx(), + rotationDegrees = rotationDegrees, + ) } } diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 09262d8..fe1cad3 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,59 +1,65 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap/ic_launcher.xml b/app/src/main/res/mipmap/ic_launcher.xml index d1b3320..b671e0e 100644 --- a/app/src/main/res/mipmap/ic_launcher.xml +++ b/app/src/main/res/mipmap/ic_launcher.xml @@ -1,21 +1,65 @@ - + - - - - - - - - - - - + android:viewportWidth="108" + android:viewportHeight="108"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap/ic_launcher_round.xml b/app/src/main/res/mipmap/ic_launcher_round.xml index d1b3320..b671e0e 100644 --- a/app/src/main/res/mipmap/ic_launcher_round.xml +++ b/app/src/main/res/mipmap/ic_launcher_round.xml @@ -1,21 +1,65 @@ - + - - - - - - - - - - - + android:viewportWidth="108" + android:viewportHeight="108"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +