21 Commits
Author SHA1 Message Date
RandyTheSilly 1ae88bdb8d Prepare for release v1.1.1 2026-10-31 14:26:03 -04:00
RandyTheSilly 9177cb7418 More guards against duplicate part swaps 2026-10-31 14:23:11 -04:00
RandyTheSilly 938dcbbd55 Tidy time/date updates 2026-10-31 14:04:34 -04:00
RandyTheSilly 20b64afe4c Eliminate unneeded variable 2026-10-31 13:58:16 -04:00
RandyTheSilly bf879d5d4c Fix potential double swaps; general cleanup 2026-10-31 12:11:32 -04:00
RandyTheSilly 3591933b5b Remove development info from README 2026-08-01 22:21:11 -04:00
RandyTheSilly 99689a6fe4 Remove tools, update copyright, update .gitignore 2026-08-01 22:20:15 -04:00
RandyTheSilly fd7fd56bf6 Remove unused palette manipulator feature 2026-06-01 20:16:59 -04:00
RandyTheSilly 106698dd5f Remove unused file 2026-05-17 00:19:34 -04:00
RandyTheSilly 0210c32d01 Add keywords 2026-04-08 19:42:31 -04:00
RandyTheSilly 80e0103e69 [Tooling] Fix hardcoded dir in clangd.zsh 2026-04-05 20:56:00 -04:00
RandyTheSilly 4674338d65 Bump version to v1.1 2026-04-05 11:23:09 -04:00
RandyTheSilly 1a496c3198 Add menu icon 2026-04-05 11:18:39 -04:00
RandyTheSilly 6b1f25f569 Fix button debug 2026-04-04 18:40:18 -04:00
RandyTheSilly 98838d5253 Fill in h/b006 (rhino) 2026-04-04 18:04:23 -04:00
RandyTheSilly db0ed68971 Invert s_first_tick; add comment 2026-04-03 16:19:04 -04:00
RandyTheSilly f0402e9d45 Fix duplicate calls to update_minute_1() 2026-04-03 15:50:54 -04:00
RandyTheSilly e568c5afea Update author name 2026-04-03 15:29:42 -04:00
RandyTheSilly 8acaefa42e Improve randomizer seeding 2026-04-03 15:25:14 -04:00
RandyTheSilly d10f5667a9 Fix part swaps occuring multiple times if the face is exited and re-opened on a 30-minute interval 2026-04-04 19:01:38 -04:00
RandyTheSilly cadf4f5783 Improve eye visibility and add extra detail for h026 2026-04-03 14:21:59 -04:00
15 changed files with 103 additions and 266 deletions

No files matched your search

+4 -2
View File
@@ -1,3 +1,5 @@
/.clangd
/build
/.lock*
/.clangd
/.lock-waf*
/package-lock.json
/node_modules
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2026 hilariouspig
Copyright (c) 2026 RandyTheSilly
THIS LICENSE DOES NOT APPLY TO ANY ".png" NOR ".ttf" FILES IN THIS REPOSITORY.
-7
View File
@@ -20,10 +20,3 @@ Since the original watchface is **NOT** open source, this "port" could be more a
- Add more Maan art (see [this gallery](https://www.flickr.com/photos/53297919@N04/albums/72157624708812279) for potential candidates)
- Potential light mode (don't hold your breath - I'm still not sure this would look good and I don't like the idea of having settings)
- Black&white support if I get bored or Pebble releases a modern b&w watch (Flint doesn't count)
# Development
1. Install the [Pebble SDK](https://developer.repebble.com/sdk/)
2. Clone this repo
3. `pebble build` (some headers needed to satisfy your IDE are generated on first build)
4. If using `clangd`, run `./tools/clangd.zsh` to generate a `.clangd` file to fix various error notifications
5. Hack away and test with `pebble build && pebble install --emulator emery`
-46
View File
@@ -1,46 +0,0 @@
/*
* Example jshint configuration file for Pebble development.
*
* Check out the full documentation at http://www.jshint.com/docs/options/
*/
{
// Declares the existence of the globals available in PebbleKit JS.
"globals": {"console": true, "setTimeout": true, "setInterval": true, "Int8Array": true, "Uint8Array": true, "Uint8ClampedArray": true, "Int16Array": true, "Uint16Array": true, "Int32Array": true, "Uint32Array": true, "Float32Array": true, "Float64Array": true, "Pebble": true, "WebSocket": true, "XMLHttpRequest": true, "navigator": true, "localStorage": true, "require": true, "exports": true, "module": true},
// Do not mess with standard JavaScript objects (Array, Date, etc)
"freeze": true,
// Do not use eval! Keep this warning turned on (ie: false)
"evil": false,
/*
* The options below are more style/developer dependent.
* Customize to your liking.
*/
// All variables should be in camelcase - too specific for CloudPebble builds to fail
// "camelcase": true,
// Do not allow blocks without { } - too specific for CloudPebble builds to fail.
// "curly": true,
// Prohibits the use of immediate function invocations without wrapping them in parentheses
"immed": true,
// Don't enforce indentation, because it's not worth failing builds over
// (especially given our somewhat lacklustre support for it)
"indent": false,
// Do not use a variable before it's defined
"latedef": "nofunc",
// Spot undefined variables
"undef": "true",
// Spot unused variables
"unused": "true",
// Enable ES6 syntax (const, let, arrow functions, etc)
"esversion": 6
}
+13 -3
View File
@@ -1,7 +1,11 @@
{
"author": "hilariouspig",
"author": "RandyTheSilly",
"dependencies": {},
"keywords": [],
"keywords": [
"silly",
"creature",
"swap"
],
"name": "maan-on-my-wrist-xl",
"pebble": {
"displayName": "Maan On My Wrist XL",
@@ -712,6 +716,12 @@
],
"type": "bitmap"
},
{
"file": "images/menu_icon.png",
"name": "MENU_ICON",
"menuIcon": true,
"type": "bitmap"
},
{
"characterRegex": "[:0-9]",
"file": "fonts/RetroComputerTime.ttf",
@@ -746,5 +756,5 @@
"watchface": true
}
},
"version": "1.0.0"
"version": "1.1.1"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

+83 -137
View File
@@ -1,9 +1,6 @@
#include "palette_manip.h"
#include <pebble.h>
// DEBUG memory usage layer
// static TextLayer *s_memory_layer;
// declare general statics
static Window *s_main_window;
static GFont s_custom_font;
@@ -69,7 +66,7 @@ static GRect s_date_grect_b;
static GRect s_bt_grect_b;
// declare animation templates
static uint8_t s_animation_duration = 255;
static const uint8_t s_animation_duration = 255;
static Animation *s_head_raise_template;
static Animation *s_head_out_template;
static Animation *s_head_in_template;
@@ -77,6 +74,9 @@ static Animation *s_butt_raise_template;
static Animation *s_butt_out_template;
static Animation *s_butt_in_template;
// guards for the swap scheduling
static struct tm s_last_swap_time;
// declare lookup tables
#if PBL_DISPLAY_WIDTH <= 180
static const uint8_t s_ones_offset[] = {0, 3, 6, 9, 12};
@@ -128,27 +128,71 @@ static void destroy_animation_handler(Animation *animation, bool finished, void
animation_destroy(animation);
}
static bool first_minute_update = true;
static void schedule_guy_animation(Animation *raise_tmpl, Animation *out_tmpl, Animation *in_tmpl, AnimationStoppedHandler out_handler) {
Animation *raise = animation_clone(raise_tmpl);
Animation *out = animation_clone(out_tmpl);
animation_set_handlers(out, (AnimationHandlers){.stopped = out_handler}, NULL);
Animation *in = animation_clone(in_tmpl);
Animation *rest = animation_clone(raise_tmpl);
animation_set_reverse(rest, true);
Animation *seq = animation_sequence_create(raise, out, in, rest, NULL);
// set the handler to destroy the sequence (and its children) when finished
animation_set_handlers(seq, (AnimationHandlers){.stopped = destroy_animation_handler}, NULL);
// run it
animation_schedule(seq);
}
static void update_minute_1() {
// get a tm structure
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
static void update_minute_30_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_butt);
s_butt_index = rand() % s_butt_count;
s_butt = gbitmap_create_with_resource(s_random_butts[s_butt_index]);
// write the current hours and minutes into a buffer & format
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_butt);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_head);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
}
static void update_minute_60_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_head);
s_head_index = rand() % s_head_count;
s_head = gbitmap_create_with_resource(s_random_heads[s_head_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_head);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_butt);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
}
static bool is_same_minute(const struct tm *a, const struct tm *b) {
return a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && a->tm_min == b->tm_min;
}
static void minute_handler(struct tm *tick_time, TimeUnits units_changed) {
// time update
static char s_time_buffer[8];
strftime(s_time_buffer, sizeof(s_time_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time);
text_layer_set_text(s_time_layer, s_time_buffer);
// write the current date into a buffer & format
// date update
static char s_date_buffer[16];
#if PBL_DISPLAY_WIDTH <= 144
strftime(s_date_buffer, sizeof(s_date_buffer), "%m%d", tick_time);
#else
strftime(s_date_buffer, sizeof(s_date_buffer), "%m.%d", tick_time);
#endif
// update layers
text_layer_set_text(s_time_layer, s_time_buffer);
text_layer_set_text(s_date_layer, s_date_buffer);
// create date/bt centering animations
@@ -163,7 +207,7 @@ static void update_minute_1() {
//// calculate new positions
s_date_grect_b = GRect(s_ones_offset[ones], s_date_pos_y, s_date_bt_width, s_date_height);
s_bt_grect_b = GRect(s_bt_pos_x - s_ones_offset[ones], s_bt_pos_y, s_date_bt_width, s_bt_height);
if (!first_minute_update) {
if (units_changed) {
//// configure animations
////// date
PropertyAnimation *date_center_prop = property_animation_create_layer_frame(text_layer_get_layer(s_date_layer), &s_date_grect_a, &s_date_grect_b);
@@ -186,79 +230,20 @@ static void update_minute_1() {
s_date_grect_a = s_date_grect_b;
s_bt_grect_a = s_bt_grect_b;
}
first_minute_update = false;
// DEBUG memory usage layer
// static char s_memory_buffer[32];
// snprintf(s_memory_buffer, sizeof(s_memory_buffer), "%d/%d", (int)heap_bytes_used(), (int)heap_bytes_free() + (int)heap_bytes_used());
// text_layer_set_text(s_memory_layer, s_memory_buffer);
}
static void schedule_guy_animation(Animation *raise_tmpl, Animation *out_tmpl, Animation *in_tmpl, AnimationStoppedHandler out_handler) {
Animation *raise = animation_clone(raise_tmpl);
Animation *out = animation_clone(out_tmpl);
animation_set_handlers(out, (AnimationHandlers){.stopped = out_handler}, NULL);
Animation *in = animation_clone(in_tmpl);
Animation *rest = animation_clone(raise_tmpl);
animation_set_reverse(rest, true);
Animation *seq = animation_sequence_create(raise, out, in, rest, NULL);
// set the handler to destroy the sequence (and its children) when finished
animation_set_handlers(seq, (AnimationHandlers){.stopped = destroy_animation_handler}, NULL);
// run it
animation_schedule(seq);
}
static void update_minute_30_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_butt);
s_butt_index = rand() % s_butt_count;
s_butt = gbitmap_create_with_resource(s_random_butts[s_butt_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_butt, NULL);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_head, NULL);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
}
static void update_minute_30() {
update_minute_1();
schedule_guy_animation(s_butt_raise_template, s_butt_out_template, s_butt_in_template, update_minute_30_out_handler);
}
static void update_minute_60_out_handler(Animation *animation, bool finished, void *context) {
// destroy and reassign
gbitmap_destroy(s_head);
s_head_index = rand() % s_head_count;
s_head = gbitmap_create_with_resource(s_random_heads[s_head_index]);
// swap colors
replace_gbitmap_color(GColorGreen, s_random_color_next, s_head, NULL);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_butt, NULL);
s_random_color_current = s_random_color_next;
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// force update bitmap layers
bitmap_layer_set_bitmap(s_guy_head_layer, s_head);
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt);
}
static void update_minute_60() {
update_minute_1();
// animate swaps on half-hour boundaries (but not on first tick)
if (units_changed & MINUTE_UNIT) {
// ignore repeated callbacks for a minute that was already swapped: a duplicate
// tick or a clock correction can move the clock back onto :00/:30
if (!is_same_minute(tick_time, &s_last_swap_time)) {
if (tick_time->tm_min == 0) {
s_last_swap_time = *tick_time;
schedule_guy_animation(s_head_raise_template, s_head_out_template, s_head_in_template, update_minute_60_out_handler);
}
static void minute_handler(struct tm *tick_time, TimeUnits units_changed) {
if (tick_time->tm_min % 60 == 0) {
update_minute_60();
} else if (tick_time->tm_min % 30 == 0) {
update_minute_30();
} else {
update_minute_1();
} else if (tick_time->tm_min == 30) {
s_last_swap_time = *tick_time;
schedule_guy_animation(s_butt_raise_template, s_butt_out_template, s_butt_in_template, update_minute_30_out_handler);
}
}
}
}
@@ -292,9 +277,6 @@ static void main_window_load(Window *window) {
layer_add_child(window_layer, text_layer_get_layer(s_date_layer));
layer_add_child(window_layer, bitmap_layer_get_layer(s_bt_layer));
// DEBUG memory usage layer
// layer_add_child(window_layer, text_layer_get_layer(s_memory_layer));
// create animation templates
//// butt raise
PropertyAnimation *butt_raise_prop = property_animation_create_layer_frame(bitmap_layer_get_layer(s_guy_butt_layer), &s_guy_butt_grect_a, &s_guy_butt_grect_b);
@@ -335,11 +317,13 @@ static void main_window_unload(Window *window) {
bitmap_layer_destroy(s_guy_butt_layer);
layer_destroy(s_time_bar_layer);
// Destroy animation templates
// destroy animation templates
animation_destroy(s_butt_raise_template);
animation_destroy(s_butt_out_template);
animation_destroy(s_butt_in_template);
animation_destroy(s_head_raise_template);
animation_destroy(s_head_out_template);
animation_destroy(s_head_in_template);
}
static void bluetooth_callback(bool connected) {
@@ -350,28 +334,16 @@ static void bluetooth_callback(bool connected) {
}
}
// DEBUG buttons
// static void up_single_click_handler(ClickRecognizerRef recognizer, void *context) {
// Window *window = (Window *)context;
// update_minute_60();
//}
// DEBUG buttons
// static void down_single_click_handler(ClickRecognizerRef recognizer, void *context) {
// Window *window = (Window *)context;
// update_minute_30();
//}
// DEBUG buttons
// static void click_config_provider(Window *window) {
// window_single_click_subscribe(BUTTON_ID_UP, up_single_click_handler);
// window_single_click_subscribe(BUTTON_ID_DOWN, down_single_click_handler);
//}
// set up the app on launch (don't put app logic in here);
static void init() {
// seed RNG
srand(time(NULL));
uint16_t seed_ms;
time_t seed_time;
time_ms(&seed_time, &seed_ms);
srand((unsigned int)seed_time ^ seed_ms);
rand();
rand();
rand(); // throw away first few values
// create main Window element and assign to pointer
s_main_window = window_create();
@@ -399,8 +371,8 @@ static void init() {
// set starting colors
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
replace_gbitmap_color(GColorGreen, s_random_color_current, s_head, NULL);
replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt, NULL);
replace_gbitmap_color(GColorGreen, s_random_color_current, s_head);
replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt);
// load custom font
#if PBL_DISPLAY_WIDTH <= 180
@@ -452,16 +424,7 @@ static void init() {
s_bt_layer = bitmap_layer_create(s_bt_grect_a);
bitmap_layer_set_compositing_mode(s_bt_layer, GCompOpSet);
bitmap_layer_set_alignment(s_bt_layer, GAlignCenter);
//// DEBUG memory usage layer
// s_memory_layer = text_layer_create(GRect(0, PBL_DISPLAY_HEIGHT - 24, PBL_DISPLAY_WIDTH, 14));
// text_layer_set_background_color(s_memory_layer, GColorClear);
// text_layer_set_font(s_memory_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14));
// text_layer_set_text_color(s_memory_layer, GColorWhite);
// PBL_IF_ROUND_ELSE(text_layer_set_text_alignment(s_memory_layer, GTextAlignmentCenter), text_layer_set_text_alignment(s_memory_layer, GTextAlignmentLeft));
// make sure the time is displayed from the start
// and that the date/bt indicators are centered
update_minute_1();
//// register with ConnectionService (bluetooth status)
connection_service_subscribe((ConnectionHandlers){.pebble_app_connection_handler = bluetooth_callback});
//// force a check to display correct bt indicator to start
@@ -475,39 +438,22 @@ static void init() {
// register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, minute_handler);
// DEBUG buttons
// window_set_click_config_provider(s_main_window, (ClickConfigProvider)click_config_provider);
}
// free memory on app exit
static void deinit() {
// unsubscribe
tick_timer_service_unsubscribe();
// destroy layers
text_layer_destroy(s_time_layer);
text_layer_destroy(s_date_layer);
bitmap_layer_destroy(s_bt_layer);
// DEBUG memory usage layer
// text_layer_destroy(s_memory_layer);
// unload font
fonts_unload_custom_font(s_custom_font);
// destroy gbitmaps
gbitmap_destroy(s_head);
gbitmap_destroy(s_butt);
gbitmap_destroy(s_bt0_icon);
gbitmap_destroy(s_bt1_icon);
// write to persistent storage
persist_write_int(storage_key_head, s_head_index);
persist_write_int(storage_key_butt, s_butt_index);
persist_write_int(storage_key_color, s_random_color_current.argb);
// destroy window
window_destroy(s_main_window);
}
+1 -11
View File
@@ -2,8 +2,6 @@
#include "palette_manip.h"
#ifdef PBL_COLOR
int get_num_palette_colors(GBitmap *b){
GBitmapFormat format = gbitmap_get_format(b);
switch (format) {
@@ -16,7 +14,7 @@ int get_num_palette_colors(GBitmap *b){
}
}
void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im, BitmapLayer *bml){
void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im){
//First determine what the number of colors in the palette
int num_palette_items = get_num_palette_colors(im);
@@ -30,12 +28,4 @@ void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, G
current_palette[i].argb = (current_palette[i].argb & 0xC0)| (replace_with_color.argb & 0x3F);
}
}
//Mark the bitmaplayer dirty
if(bml != NULL){
layer_mark_dirty(bitmap_layer_get_layer(bml));
}
}
#endif
+1 -1
View File
@@ -3,5 +3,5 @@
#include <pebble.h>
#ifdef PBL_COLOR
void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im, BitmapLayer *bml);
void replace_gbitmap_color(GColor color_to_replace, GColor replace_with_color, GBitmap *im);
#endif
-18
View File
@@ -1,18 +0,0 @@
#!/usr/bin/env zsh
echo "CompileFlags:
Add:
[
-DPBL_DISPLAY_WIDTH=200,
-DPBL_DISPLAY_HEIGHT=228,
-xc,
-nostdinc,
-DPBL_COLOR,
-I${HOME}/.pebble-sdk/SDKs/current/sdk-core/pebble/emery/include,
-include/home/cuan/gitrepos/Maan-On-My-Wrist-XL/build/include/message_keys.auto.h,
-I$(pwd)/build/emery,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/stdint.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/stdlib.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/time.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/lib/gcc/arm-none-eabi/14.2.1/include/stddef.h,
-include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/lib/gcc/arm-none-eabi/14.2.1/include/stdbool.h,
]" > ./.clangd
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env zsh
# THIS IS A LEGACY TOOL THAT WAS USED FOR THE INITIAL
# ASSET EXTRACTION - ASSETS HAVE SINCE BEEN HEAVILY
# MODIFIED, MAKING THIS SCRIPT PRETTY USELESS
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <dir> <half (top/bottom)>"
exit 1
fi
if [[ $2 == "top" ]]; then
gravity="South"
elif [[ $2 == "bottom" ]]; then
gravity="North"
else
echo "Usage: $0 <dir> <half (top/bottom)>"
exit 1
fi
for file in $1/*; do
magick "$file" -gravity $gravity -chop 0x10 "$file"
magick "$file" -transparent Black PNG24:"$file"
magick "$file" -fill "rgb(0,255,0)" -opaque White "$file"
magick "$file" -gravity Center -background None -compose Copy -extent 260x $file
# Bar is commented out for an experiment with rendering in real time on the watch
#magick "$file" -gravity $gravity -background White -splice 0x15 $file
if [[ $2 == "top" ]]; then
magick "$file" -gravity North -background None -splice 0x41 $file
else
magick "$file" -gravity South -background None -splice 0x41 $file
fi
done
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env zsh
# ALWAYS USE ZOPFLI TO CRUSH PNGS AS MUCH AS POSSIBLE BEFORE SHIPPING
for file in **/*; do
zopflipng -y --iterations=500 --filters=01234mepb --lossy_8bit --lossy_transparent $file $file &
done