You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. {% extends "main.html" %}
  2. {% block libs %}
  3. {{ super() }}
  4. <script src="js/dialog-polyfill.js"></script>
  5. {% endblock %}
  6. {% block scripts %}
  7. {{ super() }}
  8. <script>
  9. (function() {
  10. window.addEventListener('load', function() {
  11. setupDialogPolyfill();
  12. setupDialog();
  13. setupReveal();
  14. if(location.hash == '#download')
  15. document.querySelector('#bundle-dialog').showModal();
  16. });
  17. function setupDialogPolyfill()
  18. {
  19. if(typeof HTMLDialogElement === 'undefined')
  20. return;
  21. document.querySelectorAll('dialog').forEach(function(dialog) {
  22. dialogPolyfill.registerDialog(dialog);
  23. dialog.classList.add('fixed');
  24. });
  25. }
  26. function setupDialog()
  27. {
  28. if(location.search.indexOf('checkout_session_id') < 0)
  29. return;
  30. try {
  31. const searchParams = new URLSearchParams(location.search);
  32. const sessionId = searchParams.get('checkout_session_id') || '';
  33. const next = searchParams.get('next') || location.href;
  34. const url = new URL(next);
  35. url.searchParams.append('checkout_session_id', sessionId);
  36. const button = document.getElementById('download-dialog-download');
  37. const redirect = function() { location.href = url.href; };
  38. button.onclick = redirect;
  39. setTimeout(redirect, 3000);
  40. const dialog = document.getElementById('download-dialog');
  41. dialog.showModal();
  42. }
  43. catch(e) {
  44. console.error(e);
  45. alert(e.message);
  46. }
  47. }
  48. function setupReveal()
  49. {
  50. if(typeof IntersectionObserver === 'undefined')
  51. return;
  52. const observer = new IntersectionObserver(function(entries) {
  53. for(const entry of entries) {
  54. if(entry.intersectionRatio >= 0.125)
  55. entry.target.classList.remove('unrevealed');
  56. /*else if(entry.intersectionRatio == 0.0)
  57. entry.target.classList.add('unrevealed');*/
  58. }
  59. }, { threshold: [0, 0.125] });
  60. document.querySelectorAll('.reveal').forEach(function(reveal) {
  61. reveal.classList.add('unrevealed');
  62. observer.observe(reveal);
  63. });
  64. }
  65. })();
  66. </script>
  67. {% endblock %}
  68. {% block styles %}
  69. {{ super() }}
  70. <link rel="stylesheet" href="style/dialog-polyfill.css">
  71. <style>
  72. :root {
  73. --max-width: 42rem;
  74. --border-radius: 22px;
  75. --hpad: 1rem;
  76. --highlighted: #ffd500;
  77. }
  78. body {
  79. color: var(--md-default-fg-color--light);
  80. background-color: var(--md-default-bg-color);
  81. }
  82. .md-main__inner {
  83. max-width: 100% !important;
  84. margin-top: 0 !important;
  85. }
  86. .md-content__inner {
  87. margin: 0 !important;
  88. padding: 0 !important;
  89. }
  90. .md-content__inner::before {
  91. height: 0 !important;
  92. }
  93. .md-footer {
  94. color: var(--md-footer-fg-color);
  95. text-align: center;
  96. padding: 0 var(--hpad);
  97. }
  98. .md-footer .md-copyright {
  99. max-width: var(--max-width);
  100. margin-left: auto;
  101. margin-right: auto;
  102. }
  103. .md-footer a {
  104. color: var(--md-footer-fg-color--light);
  105. }
  106. /*.md-typeset h1 {
  107. font-weight: 400;
  108. }*/
  109. .md-copyright {
  110. color: var(--md-footer-fg-color--light);
  111. }
  112. #title {
  113. text-align: center;
  114. padding: 1.0rem var(--hpad) 0.5rem var(--hpad);
  115. background-image: linear-gradient(180deg,rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 1) 100%), url('img/enchanted-sky.webp');
  116. background-size: cover;
  117. background-position: center;
  118. }
  119. #title h1 {
  120. margin: 0;
  121. font-size: 3.0rem;
  122. font-weight: bold;
  123. color: #ffc;
  124. text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
  125. }
  126. #title h2 {
  127. margin: 0.5rem 0 0 0;
  128. font-size: 1.35rem;
  129. font-weight: bold;
  130. color: #ffc;
  131. text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.5);
  132. }
  133. #title video {
  134. width: 100%;
  135. max-width: var(--max-width);
  136. border-radius: var(--border-radius);
  137. margin: 1rem auto;
  138. }
  139. #topics {
  140. max-width: var(--max-width);
  141. margin-left: auto;
  142. margin-right: auto;
  143. padding: 0 var(--hpad);
  144. text-align: center;
  145. }
  146. #topics article {
  147. margin: 2rem 0;
  148. padding: 1.2rem;
  149. border-radius: var(--border-radius);
  150. background-image: linear-gradient(0deg, white 0%, lemonchiffon 100%);
  151. }
  152. #topics article:first-child {
  153. margin-top: 0.5rem;
  154. }
  155. #topics article h1 {
  156. margin-bottom: 1.0rem;
  157. }
  158. #topics article a.md-button {
  159. margin-top: 1.0rem;
  160. }
  161. #topics article p {
  162. margin: 0;
  163. }
  164. #topics article img {
  165. width: 100%;
  166. height: auto;
  167. border-radius: 16px;
  168. margin-top: 1.0rem;
  169. }
  170. #topics article ul {
  171. list-style: none;
  172. display: flex;
  173. margin: 0;
  174. }
  175. #topics article ul li {
  176. min-width: 33.33%;
  177. max-width: 50%;
  178. display: flex;
  179. align-items: center;
  180. margin: 0;
  181. }
  182. #topics article ul li img {
  183. border-radius: 0;
  184. }
  185. #contact {
  186. max-width: var(--max-width);
  187. margin-left: auto;
  188. margin-right: auto;
  189. padding: 0 var(--hpad);
  190. text-align: center;
  191. }
  192. #contact article {
  193. margin: 2rem 0;
  194. padding: 1.2rem;
  195. border-radius: var(--border-radius);
  196. background-image: linear-gradient(0deg, white 0%, lemonchiffon 100%);
  197. }
  198. #contact article h1 {
  199. margin-bottom: 1.0rem;
  200. }
  201. #contact article > div {
  202. display: flex;
  203. justify-content: space-around;
  204. flex-wrap: wrap;
  205. font-size: 1.1em;
  206. }
  207. /*
  208. #contact article a::after {
  209. content: ' \2192';
  210. }
  211. */
  212. #download {
  213. background-image: linear-gradient(0deg,rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 1) 100%), url('img/enchanted-sky.webp');
  214. background-size: cover;
  215. background-position: right bottom;
  216. /*min-height: 342px;*/
  217. }
  218. #download article {
  219. max-width: var(--max-width);
  220. margin-left: auto;
  221. margin-right: auto;
  222. padding: 2rem var(--hpad);
  223. font-size: 1.1em;
  224. text-align: center;
  225. color: #555;
  226. }
  227. #download article h1 {
  228. margin: 0;
  229. }
  230. #download article p {
  231. margin: 1.5rem 0;
  232. font-size: 1.05em;
  233. }
  234. #download article footer {
  235. display: flex;
  236. flex-wrap: wrap;
  237. justify-content: space-evenly;
  238. }
  239. #download article footer > * {
  240. margin: 0.5rem 0;
  241. }
  242. dialog {
  243. /*background-color: var(--md-default-bg-color);*/
  244. background-color: whitesmoke;
  245. color: var(--md-default-fg-color--light);
  246. text-align: center;
  247. padding: 1.5rem;
  248. border: 0;
  249. border-radius: 24px;
  250. box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.2);
  251. transition: opacity 0.5s ease;
  252. }
  253. dialog[open] {
  254. opacity: 1;
  255. }
  256. dialog:not([open]) {
  257. opacity: 0;
  258. pointer-events: none;
  259. }
  260. dialog::backdrop {
  261. backdrop-filter: blur(8px);
  262. transition: backdrop-filter 0.5s ease;
  263. }
  264. dialog h1 {
  265. margin: 1.0rem 0;
  266. font-size: 1.4rem;
  267. }
  268. dialog .close {
  269. position: absolute;
  270. top: 0.3rem;
  271. right: 0.8rem;
  272. font-size: 1.35rem;
  273. color: var(--md-default-fg-color--light);
  274. cursor: pointer;
  275. }
  276. html:has(dialog[open]) {
  277. overflow: hidden;
  278. }
  279. #bundle-dialog label {
  280. display: flex;
  281. align-items: center;
  282. text-align: left;
  283. margin-bottom: 1rem;
  284. }
  285. #bundle-dialog footer {
  286. margin-top: 1rem;
  287. }
  288. #bundle-dialog input[type="radio"] {
  289. position: absolute;
  290. opacity: 0;
  291. }
  292. #bundle-dialog button[type="submit"] {
  293. margin-top: 0.75rem;
  294. width: 100%;
  295. }
  296. #bundle-dialog label:hover {
  297. cursor: pointer;
  298. }
  299. .custom-radio {
  300. min-width: 24px;
  301. width: 24px;
  302. height: 24px;
  303. background-color: var(--md-primary-bg-color);
  304. border-radius: 50%;
  305. border: 2px solid var(--md-default-fg-color--light);
  306. margin-right: 0.75rem;
  307. }
  308. .custom-radio:hover, label:hover > .custom-radio {
  309. background-color: var(--md-default-bg-color--lighter);
  310. }
  311. .custom-radio:after {
  312. content: "";
  313. display: block;
  314. position: relative;
  315. top: 4px;
  316. left: 4px;
  317. width: 12px;
  318. height: 12px;
  319. border-radius: 50%;
  320. background: var(--md-primary-fg-color);
  321. visibility: hidden;
  322. }
  323. input[type="radio"]:checked ~ .custom-radio {
  324. border-color: var(--md-primary-fg-color);
  325. }
  326. input[type="radio"]:checked ~ .custom-radio:after {
  327. visibility: visible;
  328. }
  329. .reveal {
  330. opacity: 1;
  331. transition: transform 0.5s ease-out, opacity 0.5s ease-out;
  332. }
  333. .reveal.unrevealed {
  334. opacity: 0;
  335. transform: translateY(5rem);
  336. }
  337. @media screen and (min-width: 768px) {
  338. #title h1 { font-size: 4.0rem; }
  339. #title h2 { font-size: 1.6rem; }
  340. #topics { text-align: justify; }
  341. #topics > article img { margin-top: initial; }
  342. #topics > article { display: flex; flex-direction: row; justify-content: space-between; align-items: center; }
  343. #topics > article:nth-child(2n+1) > div:nth-child(2) { min-width: calc(var(--max-width) * 0.4); margin-left: 32px; }
  344. #topics > article:nth-child(2n) > div:nth-child(2) { min-width: calc(var(--max-width) * 0.4); margin-right: 32px; order: -1; }
  345. }
  346. @media screen and (min-width: 992px) {
  347. #topics { padding: 0; }
  348. #contact { padding: 0; }
  349. #download article footer > * { margin: 0; }
  350. }
  351. </style>
  352. {% endblock %}
  353. {% block content %}
  354. <header id="title">
  355. <h1>encantar.js</h1>
  356. <h2>High performance Web AR framework &mdash; no app required!</h2>
  357. <video autoplay loop muted playsinline controls poster="img/aframe-cat.webp">
  358. <source src="img/aframe-cat.mp4" type="video/mp4" />
  359. <source src="img/aframe-cat.webm" type="video/webm" />
  360. </video>
  361. </header>
  362. <section id="topics">
  363. <article class="reveal">
  364. <div>
  365. <h1>AR for all devices</h1>
  366. <p>Create Augmented Reality experiences for iOS, Android and even Desktops! All devices are supported, including those without native capabilities for AR / WebXR. User experience is frictionless, with no need to download apps!</p>
  367. <a href="demos/hello-aframe/poster.html" target="_blank" class="md-button" id="try-demo" data-goatcounter-click>Try a demo</a>
  368. </div>
  369. <div>
  370. <img src="img/mage.gif" alt="A mage in Augmented Reality" loading="lazy">
  371. </div>
  372. </article>
  373. <article class="reveal">
  374. <div>
  375. <h1>Turbocharged performance</h1>
  376. <p>A modern web browser is all that is required for a high performance experience, thanks to a powerful combination of GPU acceleration, WebAssembly and mathemagical wizardry. The result? A smooth user experience!</p>
  377. <a href="demos/basketball/poster.html" target="_blank" class="md-button" id="play-game" data-goatcounter-click>Play a game</a>
  378. </div>
  379. <div>
  380. <img src="img/demo-basketball.gif" alt="Magic AR Basketball Game" loading="lazy">
  381. </div>
  382. </article>
  383. <article class="reveal">
  384. <div>
  385. <h1>Open Source AR</h1>
  386. <p>encantar.js is one of the few open source Augmented Reality frameworks in existence. Your WebAR content is not tied to any platform. Host it wherever you want: there is no vendor lock-in and no usage limit.</p>
  387. <a href="tutorial/" target="_blank" class="md-button" id="read-tutorial" data-goatcounter-click>Read the tutorial</a>
  388. </div>
  389. <div>
  390. <ul>
  391. <li><img src="img/open-source.png" alt="Open Source" loading="lazy" style="margin:1.33rem"></li>
  392. <li><img src="img/lgpl.png" alt="GNU LGPL" loading="lazy"></li>
  393. </ul>
  394. </div>
  395. </article>
  396. <article class="reveal">
  397. <div>
  398. <h1>Easy to use and to deploy</h1>
  399. <p>encantar.js may be combined with A-Frame, babylon.js, three.js, or any 3D engine &ndash; you choose! Also, all processing is performed on the user's device. A static web page is all you need!</p>
  400. <a href="demos/" target="_blank" class="md-button" id="try-more-demos" data-goatcounter-click>See for yourself</a>
  401. </div>
  402. <div>
  403. <ul>
  404. <li><img src="img/logo-aframe.png" alt="A-Frame logo" loading="lazy"></li>
  405. <li><img src="img/logo-babylon.png" alt="babylon.js logo" loading="lazy"></li>
  406. <li><img src="img/logo-three.png" alt="three.js logo" loading="lazy"></li>
  407. </ul>
  408. </div>
  409. </article>
  410. <article class="reveal">
  411. <div>
  412. <h1>Enchanted Images</h1>
  413. <p>Bring images to life! Create enchanted posters, ads, books, murals and more with Image Tracking, also known as Marker Tracking or Natural Feature Tracking. Scan your own images to start the WebAR experience &ndash; all in the browser!</p>
  414. <a href="guidelines-for-images/" target="_blank" class="md-button" id="guidelines-for-images" data-goatcounter-click>View the Guidelines</a>
  415. </div>
  416. <div>
  417. <img src="img/demo-cat.gif" alt="A cat in Augmented Reality" loading="lazy">
  418. </div>
  419. </article>
  420. <article class="reveal">
  421. <div>
  422. <h1>Add-Ons</h1>
  423. <p>Add-Ons enrich the core of encantar.js with additional features, such as easy to use Buttons for triggering events, as well as a pre-built Video Player for enchanting posters, murals, business cards and more!</p>
  424. <a href="addons/" target="_blank" class="md-button" id="explore-addons" data-goatcounter-click>Explore the Add-Ons</a>
  425. </div>
  426. <div>
  427. <img src="img/video-player.gif" alt="Video player for web-based Augmented Reality" loading="lazy">
  428. </div>
  429. </article>
  430. <article class="reveal">
  431. <div>
  432. <h1>Documentation</h1>
  433. <p>Extensive documentation accompanies the software. While you can quickly get magic done just by modifying the demos, the API Spellbook provides magical formulae and a comprehensive view of the technical aspects of AR magic.</p>
  434. <a href="api/" target="_blank" class="md-button" id="open-api-reference" data-goatcounter-click>Explore the API</a>
  435. </div>
  436. <div>
  437. <img src="img/witch-coder.webp" alt="Cartoon" loading="lazy">
  438. </div>
  439. </article>
  440. </section>
  441. <section id="contact">
  442. <article class="reveal">
  443. <h1>Need help?</h1>
  444. <p>Usually you can go a long way with the publicly available resources, which include the written materials and the various demos. If you need one-to-one assistance, consultancy services are available.</p>
  445. <a href="contact/" target="_blank" class="md-button" id="talk-to-wizard" data-goatcounter-click>Talk to a wizard</a>
  446. </article>
  447. </section>
  448. <section id="download">
  449. <article>
  450. <h1>Download</h1>
  451. <p>encantar.js is created independently by <a href="contact/" target="_blank" id="author-name" data-goatcounter-click>Alexandre Martins</a>. It's based on <a href="https://github.com/alemart/speedy-vision" target="_blank" rel="external" id="speedy-vision" data-goatcounter-click>speedy-vision</a>, an open source computer vision library created by the same author. Your support is much appreciated!</p>
  452. <footer>
  453. <button class="md-button md-button--primary" id="download-button" data-goatcounter-click onclick="document.getElementById('bundle-dialog').showModal()">Download encantar.js</button>
  454. <a href="https://github.com/sponsors/alemart" target="_blank" class="md-button" id="download-sponsor" data-goatcounter-click>Sponsor on GitHub</a>
  455. </footer>
  456. </article>
  457. </section>
  458. <footer class="md-footer">
  459. <div class="md-copyright">
  460. encantar.js: GPU-accelerated Augmented Reality framework for the web. Copyright &copy; 2022 &ndash; present Alexandre Martins
  461. </div>
  462. </footer>
  463. <dialog id="bundle-dialog" class="fixed">
  464. <h1>Select an option</h1>
  465. <form autocomplete="off" onsubmit="location.href = this.elements.bundle.value; return false">
  466. <label>
  467. <input type="radio" name="bundle" value="https://ko-fi.com/s/3ee4182cb6" checked data-goatcounter-click>
  468. <span class="custom-radio"></span>
  469. <div>
  470. <strong>Standard Bundle</strong><br>
  471. Production-ready, pre-built encantar.js with core features and demos
  472. </div>
  473. </label>
  474. <label>
  475. <input type="radio" name="bundle" value="https://ko-fi.com/s/697a184728" data-goatcounter-click>
  476. <span class="custom-radio"></span>
  477. <div>
  478. <strong>Plus Bundle</strong><br>
  479. encantar.js with <a href="addons/" id="exclusive-addons" target="_blank" data-goatcounter-click>exclusive Add-Ons for rich AR experiences</a>
  480. </div>
  481. </label>
  482. <label>
  483. <input type="radio" name="bundle" value="https://github.com/alemart/encantar-js" data-goatcounter-click>
  484. <span class="custom-radio"></span>
  485. <div>
  486. <strong>Source Code</strong><br>
  487. For Augmented Reality and Computer Vision nerds
  488. </div>
  489. </label>
  490. <footer>
  491. <button type="submit" class="md-button md-button--primary" id="download-bundle" data-goatcounter-click>OK</button>
  492. </footer>
  493. </form>
  494. <button id="donation-dialog-close" class="close" onclick="this.parentNode.close()">&times;</button>
  495. </dialog>
  496. {% endblock %}
  497. {% block announce %}{% endblock %}
  498. {% block header %}{% endblock %}
  499. {% block tabs %}{% endblock %}
  500. {% block site_nav %}{% endblock %}
  501. {% block footer %}{% endblock %}