Created
August 23, 2025 15:15
-
-
Save laiso/5fb0d949755c9f7d6c96edd1beea45f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.nothinglondon.sdkdemo.demos.sushi | |
import android.content.Context | |
import com.nothing.ketchum.GlyphMatrixManager | |
import com.nothinglondon.sdkdemo.demos.GlyphMatrixService | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.cancel | |
import kotlinx.coroutines.delay | |
import kotlinx.coroutines.isActive | |
import kotlinx.coroutines.launch | |
import kotlin.math.abs | |
import kotlin.math.max | |
import kotlin.math.min | |
/** | |
* High-contrast maki-sushi pixel art for a 25x25 monochrome matrix. | |
* Techniques: bright outline, rice dithering, inner filling dot, rim highlight shimmer. | |
*/ | |
class ShushiDemoService : GlyphMatrixService("Shushi-Demo") { | |
private val bgScope = CoroutineScope(Dispatchers.Default) | |
override fun performOnServiceConnected( | |
context: Context, | |
glyphMatrixManager: GlyphMatrixManager | |
) { | |
// Subtle loop to add a glint over the fish, improving recognizability of nigiri. | |
bgScope.launch { | |
var t = 0 | |
while (isActive) { | |
val frame = buildNigiriFrame(t) | |
glyphMatrixManager.setMatrixFrame(frame) | |
delay(80L) | |
t = (t + 1) % 32 | |
} | |
} | |
} | |
override fun performOnServiceDisconnected(context: Context) { | |
bgScope.cancel() | |
} | |
private fun buildNigiriFrame(tick: Int): IntArray { | |
val w = 25 | |
val h = 25 | |
val grid = IntArray(w * h) { 0 } | |
fun set(x: Int, y: Int, v: Int) { | |
if (x in 0 until w && y in 0 until h) grid[y * w + x] = v.coerceIn(0, 255) | |
} | |
fun insideCapsule( | |
x: Int, | |
y: Int, | |
cx: Double, | |
cy: Double, | |
halfRect: Int, | |
r: Int | |
): Boolean { | |
val dx = x - cx | |
val dy = y - cy | |
if (abs(dx) <= halfRect && abs(dy) <= r) return true | |
val leftCx = cx - halfRect | |
val rightCx = cx + halfRect | |
val dl = (x - leftCx) * (x - leftCx) + (y - cy) * (y - cy) | |
val dr = (x - rightCx) * (x - rightCx) + (y - cy) * (y - cy) | |
return dl <= (r * r) || dr <= (r * r) | |
} | |
// Brightness palette (0..255) | |
val B_PLATE = 50 | |
val B_RICE = 185 | |
val B_RICE_DOT = 215 | |
val B_FISH = 230 | |
val B_FISH_STRIPE = 150 | |
val B_EDGE = 90 | |
// Plate shadow (subtle) under the rice | |
for (y in 21..22) for (x in 7..17) set(x, y, B_PLATE) | |
// Rice capsule parameters | |
val cxRice = w / 2.0 | |
val cyRice = 17.0 | |
val riceHalfRect = 5 // rectangle half-width between rounded ends | |
val riceR = 3 // end radius and half-height | |
// Rice fill with light dithering | |
for (y in 0 until h) { | |
for (x in 0 until w) { | |
if (insideCapsule(x, y, cxRice, cyRice, riceHalfRect, riceR)) { | |
var v = B_RICE | |
val m = (x * 3 + y * 5) and 7 | |
if (m == 0 || m == 5) v = B_RICE_DOT | |
set(x, y, v) | |
} | |
} | |
} | |
// Fish (top slab) parameters | |
val cxFish = w / 2.0 | |
val cyFish = 13.0 | |
val fishHalfRect = 6 | |
val fishR = 2 | |
// Moving diagonal highlight band across fish | |
val mod = 14 | |
val phase = tick % mod | |
for (y in 0 until h) { | |
for (x in 0 until w) { | |
if (insideCapsule(x, y, cxFish, cyFish, fishHalfRect, fishR)) { | |
var v = B_FISH | |
// Diagonal darker stripes to imply salmon texture | |
val stripe = ((x - y) and 3) == 0 | |
if (stripe) v = min(v, B_FISH_STRIPE) | |
// Shimmering highlight band | |
val band = (x + y - phase + 1280) % mod | |
if (band in 0..1) v = max(v, 255) | |
set(x, y, v) | |
} | |
} | |
} | |
// Thin separation edge (shadow) just below fish | |
for (y in 1 until h) { | |
for (x in 0 until w) { | |
val above = grid[(y - 1) * w + x] | |
val here = grid[y * w + x] | |
// If above is fish-ish bright and here is rice-ish, add a darker edge | |
if (above >= 200 && here in (B_RICE - 20)..(B_RICE_DOT + 10)) { | |
grid[y * w + x] = B_EDGE | |
} | |
} | |
} | |
return grid | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment