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"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +