' . '<' . 'use xlink:href="#tear" x="7" transform="scale(0.8)"/>'; $v = ($_GET['v'] ?? 50)/100; $a = $_GET['a']; $a1 = ($_GET['a1'] ?? $a ?? 50)/100; $a2 = ($_GET['a2'] ?? $a ?? 50)/100; $d = ($_GET['d'] ?? 50)/100; $c = ($_GET['c'] ?? 0)/100; $g = ($_GET['g'] ?? 0)/100; $b = ($_GET['b'] ?? 0)/100; $t = ($_GET['t'] ?? 0)/100; $speak = $_GET['speak_rate'] ?? 0; $blink = $_GET['blink_rate'] ?? 0; $invert = ($_GET['invert'] ?? 0)/100; $color = $_GET['color'] ?? null; $o = $_GET['o']; if (!is_null($o)) { $a = ($a1+$a2)/2; $a1 = $a + $o/100 - 0.5; $a2 = $a - $o/100 + 0.5; } $size = $_GET['size']; if ($size) { $template = preg_replace('/100%/', $size, $template, 2); } function dotprod($X, $Y) { $value = 0; for ($j = 0; $j < count($Y); $j++) { $value += $Y[$j] * $X[$j]; } return $value; } function render($template, $data, $V) { $index = 0; return preg_replace_callback('/\?/', function() use (&$index, $V, $data) { return dotprod($V, $data[$index++]); }, $template); } function color_palette($inv, $hue) { $l = fn($x) => sprintf('%.3f', 1 - $x); $c = fn($x) => sprintf('%.3f', 1.6*$x*(1-$x) - 3*$x*($x-0.5)*($x-1)); return 'light-dark(oklch('.$l($inv).' '.$c($inv).' '.$hue.'),oklch('.$l(1-$inv).' '.$c(1-$inv).' '.$hue.'))'; } function invertable_darkmode($inv, $svg, $color = null) { if (is_null($color)) { $stroke = color_palette(1 - $inv, 14); $svg = preg_replace('/(]*>)/', '$1', $svg, 1); } $fill = color_palette($inv, 194); if ($inv>0) { $svg = preg_replace('/(]*>)/', '$1', $svg, 1); } $stroke = is_null($color) ? 'currentColor' : htmlspecialchars($color, ENT_QUOTES); return str_replace('stroke="black"', 'stroke="'.$stroke.'"', $svg); } function paramoji_svg($v, $a1, $a2, $d, $g, $c, $b, $t) { global $template, $data; return render($template, $data, [1, 2*$v-1, $a1, $a2, 2*$d-1, $g, $c, $b, $t]); } function animate_tag($id, $attrs, $speed, $path) { $tag = '/id="' . $id . '"[^>]*>/'; $dur = 60 / $speed; $keyTimes = implode(';', array_map(function($k) { return floatval($k) / 100; }, array_keys($path))); $svgs = array_values($path); $value = function($svg, $attr) use ($tag) { preg_match($tag, $svg, $m); preg_match('/\b' . $attr . '="([^"]*)"/', $m[0], $mm); return $mm[1]; }; $animate = ''; foreach ($attrs as $attr) { $values = implode(';', array_map(function($svg) use ($value, $attr) { return $value($svg, $attr); }, $svgs)); $animate .= ''; } return preg_replace_callback($tag, function($m) use ($animate) { return $m[0] . $animate; }, $svgs[0], 1); } $svg = paramoji_svg($v, $a1 + 0.0001*$blink, $a2 + 0.002*$speak, $d, $g, $c, $b, $t); if ($blink > 0) { $closed = paramoji_svg((1-$a1)*$v, 0, $a2, $d, $g, $c, $b, $t); $svg = animate_tag('eye', ['d', 'transform'], $blink, [ '0%' => $svg, '80%' => $svg, '88%' => $closed, '90%' => $closed, '100%' => $svg, ]); } if ($speak > 0) { $speaking = paramoji_svg($v, $a1, 0, $d, $g, $c, $b, $t); $speaking2 = paramoji_svg($v, $a1, $a2*0.5, $d, $g, $c, $b, $t); $svg = animate_tag('lips', ['d', 'transform'], $speak, [ '0%' => $svg, '25%' => $svg, '30%' => $speaking, '45%' => $speaking2, '55%' => $speaking, '75%' => $svg, '100%' => $svg, ]); } $svg = invertable_darkmode($invert, $svg, $color); echo $svg; ?>