File size: 5,048 Bytes
26dae50
 
 
 
 
df6b3ac
26dae50
 
 
 
f7a11cd
df6b3ac
26dae50
 
f7a11cd
df6b3ac
 
 
 
 
 
 
f7a11cd
df6b3ac
 
f8f5696
e62437d
 
 
 
f8f5696
 
df6b3ac
26dae50
df6b3ac
26dae50
 
f7a11cd
df6b3ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26dae50
dc59186
 
 
 
 
 
 
 
 
 
 
1f8aca6
 
dc59186
 
 
 
214efbc
250c08a
 
dc59186
 
 
26dae50
2bdcfe3
 
 
 
26dae50
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
  <meta name="theme-color" content="#05060a" />
  <title>Iris</title>
  <link rel="stylesheet" href="/static/style.css" />
</head>
<body>
  <!-- live camera (background) -->
  <video id="cam" autoplay playsinline muted aria-hidden="true"></video>
  <canvas id="canvas" hidden></canvas>

  <!-- top bar: accessibility + language -->
  <header id="topbar">
    <button id="a11y" class="chip" aria-pressed="false" aria-label="High contrast and larger text">
      <span aria-hidden="true">Aa</span>
    </button>
    <button id="lang" class="chip" aria-label="Language">PT</button>
  </header>

  <!-- stage: the whole screen is tappable (tap=describe, hold=ask, double-tap=live) -->
  <main id="stage" aria-label="Iris. Tap to describe, hold to ask, double tap for live mode.">
    <div id="halo" aria-hidden="true"></div>
    <div id="brand" aria-hidden="true">
      <svg viewBox="0 0 120 120" class="iris-mark">
        <path d="M14 60 Q60 26 106 60 Q60 94 14 60 Z" fill="none" stroke="#fff" stroke-width="3.2" stroke-linejoin="round" opacity=".92"/>
        <circle cx="60" cy="60" r="17" fill="none" stroke="#fff" stroke-width="3.2" opacity=".92"/>
        <circle cx="60" cy="60" r="6" fill="#ff7a18"/>
      </svg>
    </div>
    <p id="status" role="status" aria-live="assertive">Iris</p>
    <p id="answer" aria-live="polite"></p>
    <p id="hint" aria-hidden="true"></p>
  </main>

  <!-- explicit controls (low vision / keyboard / screen reader) -->
  <nav id="controls" aria-label="Actions">
    <button id="btn-ask" class="ctl" aria-label="Ask a question. Press and hold, then speak.">
      <span class="ic" aria-hidden="true">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <rect x="9" y="2" width="6" height="12" rx="3"/><path d="M5 11a7 7 0 0 0 14 0"/><line x1="12" y1="18" x2="12" y2="22"/>
        </svg>
      </span><span class="ctl-lbl">Ask</span>
    </button>
    <button id="btn-describe" class="ctl primary" aria-label="Describe what is in front of me">
      <span class="ic" aria-hidden="true">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/>
        </svg>
      </span><span class="ctl-lbl">Describe</span>
    </button>
    <button id="btn-live" class="ctl" aria-pressed="false" aria-label="Live mode: announce new things around you">
      <span class="ic" aria-hidden="true">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="12" cy="12" r="2"/><path d="M16.2 7.8a6 6 0 0 1 0 8.5M7.8 16.2a6 6 0 0 1 0-8.5M19 5a10 10 0 0 1 0 14M5 19A10 10 0 0 1 5 5"/>
        </svg>
      </span><span class="ctl-lbl">Live</span>
    </button>
  </nav>

  <!-- welcome popup: shows on every open, reads the pitch aloud, closeable by voice/tap -->
  <div id="intro" role="dialog" aria-modal="true" aria-labelledby="intro-title" aria-describedby="intro-body">
    <div class="intro-card" role="document">
      <button id="intro-replay" class="intro-mark" aria-label="Replay the introduction">
        <svg viewBox="0 0 120 120" class="iris-mark" aria-hidden="true">
          <path d="M14 60 Q60 26 106 60 Q60 94 14 60 Z" fill="none" stroke="#fff" stroke-width="3.2" stroke-linejoin="round" opacity=".92"/>
          <circle cx="60" cy="60" r="17" fill="none" stroke="#fff" stroke-width="3.2" opacity=".92"/>
          <circle cx="60" cy="60" r="6" fill="#ff7a18"/>
        </svg>
      </button>
      <h2 id="intro-title">Iris</h2>
      <p id="intro-body">This is Iris, your eyes by voice. It reads your money, your bills, and your medicine, out loud.</p>
      <p id="intro-how" class="intro-how">Tap to describe · Hold to ask · Double-tap (or say "live mode") for live mode</p>
      <div class="intro-langs" role="group" aria-label="Language">
        <button id="intro-en" class="intro-lang">EN</button>
        <button id="intro-pt" class="intro-lang">PT</button>
      </div>
      <a id="intro-video" class="intro-video" href="https://youtu.be/h4AJOWuDCVc" target="_blank" rel="noopener">Watch the demo</a>
      <button id="intro-close" class="intro-close">Close</button>
      <p id="intro-hint" class="intro-hint">Say "close" or tap the button</p>
    </div>
  </div>

  <audio id="player" playsinline></audio>

  <!-- in-browser object detection (gates live mode); falls back to pixel-diff if unavailable -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4"></script>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd@2"></script>
  <script type="module" src="/static/app.js"></script>
</body>
</html>