Add news update: The Accessibility Update

main
Isaiah Odhner 2020-12-19 17:49:10 -05:00
parent eb4af4d7f9
commit badb503d09
4 changed files with 204 additions and 11 deletions

View File

@ -85,6 +85,111 @@
</p>
</div>
<div id="news" hidden>
<article class="news-entry" id="news-2020-accessibility-update">
<h1>The Accessibility Update</h1>
<time datetime="2020-12-20">2020-12-20</time>
<img width="654" height="314" style="max-width: 100%; height: auto;" src="https://i.postimg.cc/LsjTZ2tW/accessibility-update.png"/>
<h2>Multi-Lingual Support</h2>
<p>JS Paint is now largely localized into 26 languages.</p>
<p>
How am I releasing so many languages at the initial release of multi-lingual support, you may ask?
Well, this project has the somewhat unique opportunity to reuse localizations from an existing program, since it's primarily a remake of MS Paint.
</p>
<p>
I downloaded and installed <a target="_blank" href="https://postimg.cc/4Y1V24wN">26 versions of Windows 98 in virtual machines</a>,
and extracted text from mspaint.exe in each one of them,
using a set of complex scripts that I wrote to to help me automate the process.
It took about two weeks of work.
</p>
<p>
To change the language, go to <b>Extras > Language</b>.
Your prefered language may already be detected, if specified in system or browser settings.
</p>
<img width="1280" height="720" style="max-width: 100%; height: auto;" src="https://i.postimg.cc/G2bH92fp/language-menu.png"/>
<p>For Arabic and Hebrew, right-to-left layout is supported!</p>
<p>I tried my hand at some Arabic calligraphy...</p>
<img width="1141" height="800" style="max-width: 100%; height: auto;" src="https://i.postimg.cc/NFX2TTp1/untitled-45.png"/>
<p>
If you want to contribute translations, <a target="_blank" href="https://github.com/1j01/jspaint/issues/80">get in touch!</a>
I need to do some technical work to set up for community translations on a public platform,
but I'm glad people have already expressed interest in helping translate!
(I also want to simplify the language in various parts of the UI before asking people to translate them.)
</p>
<h2>Eye Gaze Mode</h2>
<p>Eye Gaze Mode lets you control JS Paint without using your hands.</p>
<p>It's intended for use with an eye tracker, head tracker, or other coarse input scenario.</p>
<p>You don't need a thousand-dollar eye tracker device to play around with this, just a webcam and some free software.</p>
<p>
I recommend <a target="_blank" href="https://eviacam.crea-si.com/">Enable Viacam</a>, which is <em>not</em> an eye gaze tracker,
but rather a general video movement tracker that you can set up to track your head movement (or your torso or hand or anything else).
</p>
<p>
Eye tracking via a webcam has a ways to go, but it's also pretty amazing in its own right.
Try <a target="_blank" href="https://sourceforge.net/projects/gazepointer/">GazePointer</a>.
</p>
<p>
Eye gaze tracking requires significant calibration, and if the callibration is off,
it's hard to use because you can't look where you want to look to interact with things.
This is why I recommend head tracking (if that's an option for you),
because then you can freely look around, and control the cursor <em>independently</em>,
so if it gets offset, you can just tilt your head a bit.
</p>
<p>
Eye Gaze Mode is built mainly for people with movement disabilities like ALS or Cerebral Palsy,
but it can also just be a sort of magical experience.
It can also be frustrating, and takes some practice to master.
</p>
<p>
Access with <b>Extras > Eye Gaze Mode</b> and note that it will start clicking where you hover.
You can disable this dwell clicking with the eye icon in the bottom of the screen.
</p>
<p>
<span class="new">Bonus:</span> Since I implemented a vertical color box for Eye Gaze Mode,
I decided to make this available as a separate option. Access with <b>Extras > Vertical Color Box</b>.
</p>
<h2>Speech Recognition</h2>
<p>
Using only your voice, you can switch tools and colors, pan the view, click on buttons on the screen by name, and use most menu items.
You can even say "draw a cat in a party hat" to have JS Paint try to sketch a cat in a party hat.
</p>
<p>This feature pairs well with Eye Gaze Mode for a more complete hands free experience.</p>
<p>
The feature is only available on Chrome, and only understands English.
Note that Chrome sends your voice to Google servers.
(Developers, please work on speech recognition support in Firefox!)
</p>
<p>Access with <b>Extras > Speech Recognition</b>. If this option is grayed out, your browser is not supported.</p>
<p>JS Paint will show what it thinks you said in the status bar at the bottom of the screen.</p>
<p>
There are many synonyms for commands, and often you can do things with very short phrases like "Curve" to switch to the Curve tool.
If it's not recognizing your voice for short commands like "Curve" or "Cut", you may want to try longer phrases like "Curve tool" or "Cut selection",
as this helps it distinguish the sound as speech, rather than a cough for instance.
</p>
<h2>Edit Colors Dialog</h2>
<p>I also implemented the Edit Colors dialog. Previously this used the native system color picker, and didn't work for some people.</p>
<p>Access with <b>Colors > Edit Colors</b> or double click a color in the palette to edit.</p>
<figure>
<img width="496" height="350" style="max-width: 100%; height: auto;" src="https://i.postimg.cc/cLNgWH0r/Peek-2020-12-04-00-31.gif"/>
<figcaption>An animation morphing between JS Paint and MS Paint's color picking dialog. It's pretty close, other than the font.</figcaption>
</figure>
<p>Keyboard shortcuts are supported in this dialog, and for mobile devices with small screens, I made it treat adding custom colors as a separate screen.</p>
<h2>Conclusion</h2>
<p>
JS Paint is way more accessible now. And futuristic. And cool.
<p>
<p>
Of course there's always more that could be done.
Eye Gaze Mode could use brush stroke smoothing, and Speech Recognition could use general artificial intelligence.
</p>
</p>
I'd love to see people using JS Paint, especially the Eye Gaze Mode and Speech Recognition,
so please, if you don't mind, record yourself on video and
<a target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSdGgS6TS4wBV89v8NoYHenh1eI8jYBfgwYBdPx-OaCEG5EW7g/viewform?usp=sf_link">send me the video through this form.</a>
Maybe I could even make a compilation video.
But mainly this lets me know what's actually important to people, and what's confusing,
and it gives me motivation to work more on new features.
</p>
</article>
<article class="news-entry" id="news-2019-winter-update">
<h1>Winter Update</h1>
<time datetime="2019-12-20">2019-12-20</time>

View File

@ -272,8 +272,10 @@ const $status_size = $(E("div")).addClass("status-coordinates").appendTo($status
const $news_indicator = $(`
<a class='news-indicator' href='#project-news'>
<img src='images/winter/present.png' width='24' height='22' alt=''/>
<span class='not-the-icon'>
<strong>New!</strong>&nbsp;Holiday theme, multitouch panning, and revamped history
<span class='marquee' dir='ltr' style='--text-width: 52ch; --animation-duration: 5s;'>
<span>
<strong>New!</strong>&nbsp;Localization, Eye Gaze Mode, and Speech Recognition!
</span>
</span>
</a>
`);
@ -283,7 +285,7 @@ $news_indicator.on("click auxclick", (event)=> {
});
// @TODO: use localstorage to show until clicked, if available
// and show for a longer period of time after the update, if available
if (Date.now() < Date.parse("Jan 5 2020 23:42:42 GMT-0500")) {
if (Date.now() < Date.parse("Jan 5 2021 23:42:42 GMT-0500")) {
$status_area.append($news_indicator);
}

View File

@ -631,7 +631,7 @@ html, body, .jspaint {
/* Fix label ordering for RTL layout (display inline labels can get super out of order with the checkboxes/inputs - very confusing!) */
.window-content label {
display: inline-flex;
display: inline-flex;
flex-direction: row;
direction: ltr;
}
@ -651,7 +651,7 @@ html, body, .jspaint {
}
/* @TODO: part of os-gui */
.os-window .window-content {
flex: 1;
flex: 1;
}
.help-window .window-content {
@ -840,22 +840,65 @@ html, body, .jspaint {
}
.news-indicator {
display: flex;
font-family: sans-serif;
}
.news-indicator > img {
margin-right: 5px;
}
@media (max-width: 500px) {
@media (max-width: 550px) {
.news-indicator > img {
position: absolute;
right: 0;
bottom: 0;
}
.news-indicator .not-the-icon {
.news-indicator .marquee {
display: none;
}
}
.marquee {
overflow: hidden;
text-decoration: inherit;
}
.marquee span {
display: inline-block;
white-space: nowrap;
width: var(--text-width);
text-shadow:
var(--text-width) 0 currentColor,
calc(var(--text-width) * 2) 0 currentColor,
calc(var(--text-width) * 3) 0 currentColor,
calc(var(--text-width) * 4) 0 currentColor;
will-change: transform;
animation: marquee var(--animation-duration) linear infinite;
animation-play-state: paused;
text-decoration: inherit;
}
.marquee:hover span {
animation-play-state: running;
}
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
/* On MacOs: System Preferences > Accessibility > Display > Reduce motion */
@media (prefers-reduced-motion: reduce) {
.marquee span {
animation: none;
text-shadow: none;
width: auto;
display: block;
line-height: 1.5;
text-align: center;
white-space: normal;
}
}
[touch-action="none"] {
touch-action: none;
}

View File

@ -631,7 +631,7 @@ html, body, .jspaint {
/* Fix label ordering for RTL layout (display inline labels can get super out of order with the checkboxes/inputs - very confusing!) */
.window-content label {
display: inline-flex;
display: inline-flex;
flex-direction: row;
direction: rtl;
}
@ -651,7 +651,7 @@ html, body, .jspaint {
}
/* @TODO: part of os-gui */
.os-window .window-content {
flex: 1;
flex: 1;
}
.help-window .window-content {
@ -840,22 +840,65 @@ html, body, .jspaint {
}
.news-indicator {
display: flex;
font-family: sans-serif;
}
.news-indicator > img {
margin-left: 5px;
}
@media (max-width: 500px) {
@media (max-width: 550px) {
.news-indicator > img {
position: absolute;
left: 0;
bottom: 0;
}
.news-indicator .not-the-icon {
.news-indicator .marquee {
display: none;
}
}
.marquee {
overflow: hidden;
text-decoration: inherit;
}
.marquee span {
display: inline-block;
white-space: nowrap;
width: var(--text-width);
text-shadow:
var(--text-width) 0 currentColor,
calc(-1*(var(--text-width) * 2)) 0 currentColor,
calc(-1*(var(--text-width) * 3)) 0 currentColor,
calc(-1*(var(--text-width) * 4)) 0 currentColor;
will-change: transform;
animation: marquee var(--animation-duration) linear infinite;
animation-play-state: paused;
text-decoration: inherit;
}
.marquee:hover span {
animation-play-state: running;
}
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(100%); }
}
/* On MacOs: System Preferences > Accessibility > Display > Reduce motion */
@media (prefers-reduced-motion: reduce) {
.marquee span {
animation: none;
text-shadow: none;
width: auto;
display: block;
line-height: 1.5;
text-align: center;
white-space: normal;
}
}
[touch-action="none"] {
touch-action: none;
}