index.html 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>nEngine Editor</title>
  7. <style>
  8. html,
  9. body {
  10. margin: 0;
  11. height: 100%;
  12. background: #171b20;
  13. color: #e6e9ec;
  14. font-family: system-ui, sans-serif;
  15. font-size: 14px;
  16. }
  17. #app {
  18. display: flex;
  19. flex-direction: column;
  20. height: 100%;
  21. }
  22. .screen {
  23. flex: 1;
  24. display: flex;
  25. flex-direction: column;
  26. padding: 24px;
  27. gap: 12px;
  28. overflow: auto;
  29. }
  30. .hidden {
  31. display: none;
  32. }
  33. h1 {
  34. margin: 0;
  35. font-size: 28px;
  36. color: #a5d6a7;
  37. }
  38. h2 {
  39. margin: 24px 0 8px;
  40. font-size: 15px;
  41. color: #90a4ae;
  42. text-transform: uppercase;
  43. letter-spacing: 0.08em;
  44. }
  45. h3 {
  46. margin: 0 0 8px;
  47. font-size: 13px;
  48. color: #90a4ae;
  49. text-transform: uppercase;
  50. letter-spacing: 0.08em;
  51. }
  52. button {
  53. font: inherit;
  54. padding: 7px 16px;
  55. border: 1px solid #4a5560;
  56. border-radius: 5px;
  57. background: #262c34;
  58. color: #e6e9ec;
  59. cursor: pointer;
  60. }
  61. button:hover {
  62. background: #313a45;
  63. }
  64. button.primary {
  65. background: #2e7d32;
  66. border-color: #66bb6a;
  67. }
  68. button.primary:hover {
  69. background: #388e3c;
  70. }
  71. #home-actions {
  72. display: flex;
  73. gap: 10px;
  74. }
  75. #recent-list {
  76. list-style: none;
  77. margin: 0;
  78. padding: 0;
  79. display: flex;
  80. flex-direction: column;
  81. gap: 6px;
  82. max-width: 560px;
  83. }
  84. #recent-list button {
  85. width: 100%;
  86. text-align: left;
  87. display: flex;
  88. justify-content: space-between;
  89. gap: 12px;
  90. }
  91. #recent-list .recent-path {
  92. color: #7f8c99;
  93. font-size: 12px;
  94. }
  95. .muted {
  96. color: #7f8c99;
  97. }
  98. #home-error {
  99. color: #ef5350;
  100. min-height: 18px;
  101. }
  102. #topbar {
  103. display: flex;
  104. align-items: center;
  105. gap: 14px;
  106. padding: 10px 16px;
  107. background: #1f242b;
  108. border-bottom: 1px solid #2d343d;
  109. }
  110. #project-name {
  111. font-weight: 600;
  112. color: #a5d6a7;
  113. }
  114. #project-path {
  115. color: #7f8c99;
  116. font-size: 12px;
  117. flex: 1;
  118. min-width: 0;
  119. overflow: hidden;
  120. text-overflow: ellipsis;
  121. white-space: nowrap;
  122. }
  123. #mcp-url {
  124. color: #7f8c99;
  125. font-size: 12px;
  126. font-family: ui-monospace, monospace;
  127. max-width: 280px;
  128. overflow: hidden;
  129. text-overflow: ellipsis;
  130. white-space: nowrap;
  131. }
  132. #mcp-url.running {
  133. color: #a5d6a7;
  134. }
  135. #workspace {
  136. flex: 1;
  137. display: flex;
  138. min-height: 0;
  139. }
  140. #content-browser {
  141. width: 240px;
  142. border-right: 1px solid #2d343d;
  143. padding: 14px;
  144. overflow: auto;
  145. background: #1c2127;
  146. }
  147. #content-list {
  148. list-style: none;
  149. margin: 0;
  150. padding: 0;
  151. display: flex;
  152. flex-direction: column;
  153. gap: 3px;
  154. }
  155. #content-list li {
  156. display: flex;
  157. justify-content: space-between;
  158. align-items: center;
  159. padding: 4px 8px;
  160. border-radius: 4px;
  161. font-size: 13px;
  162. }
  163. #content-list li:hover {
  164. background: #262c34;
  165. }
  166. #content-list li.clickable {
  167. cursor: pointer;
  168. }
  169. .kind-name {
  170. color: #cfd8dc;
  171. }
  172. .kind-count {
  173. color: #7f8c99;
  174. font-variant-numeric: tabular-nums;
  175. }
  176. .kind-files {
  177. list-style: none;
  178. margin: 2px 0 0 10px;
  179. padding: 0;
  180. display: flex;
  181. flex-direction: column;
  182. gap: 2px;
  183. }
  184. .kind-file {
  185. font-size: 12px;
  186. padding: 3px 8px;
  187. text-align: left;
  188. width: 100%;
  189. background: #1f242b;
  190. }
  191. .kind-file:hover {
  192. background: #313a45;
  193. }
  194. .kind-new {
  195. padding: 2px 9px;
  196. font-size: 13px;
  197. line-height: 1.2;
  198. flex: none;
  199. }
  200. #editor-panel {
  201. flex: 1;
  202. padding: 16px;
  203. display: flex;
  204. flex-direction: column;
  205. gap: 8px;
  206. min-width: 0;
  207. }
  208. #editor-panel .placeholder {
  209. color: #7f8c99;
  210. border: 1px dashed #2d343d;
  211. border-radius: 6px;
  212. padding: 32px;
  213. text-align: center;
  214. }
  215. .form-panel {
  216. display: flex;
  217. flex-direction: column;
  218. gap: 10px;
  219. flex: 1;
  220. min-height: 0;
  221. }
  222. .form-header {
  223. display: flex;
  224. align-items: center;
  225. gap: 10px;
  226. flex-wrap: wrap;
  227. }
  228. .form-header h3 {
  229. margin: 0;
  230. }
  231. .form-path {
  232. color: #7f8c99;
  233. font-size: 12px;
  234. flex: 1;
  235. min-width: 0;
  236. overflow: hidden;
  237. text-overflow: ellipsis;
  238. white-space: nowrap;
  239. }
  240. .form-errors {
  241. color: #ef5350;
  242. font-size: 12px;
  243. max-height: 140px;
  244. overflow: auto;
  245. }
  246. .form-errors ul {
  247. margin: 0;
  248. padding-left: 18px;
  249. }
  250. .form-body {
  251. flex: 1;
  252. min-height: 0;
  253. overflow: auto;
  254. display: flex;
  255. flex-direction: column;
  256. gap: 10px;
  257. padding: 10px;
  258. background: #1c2127;
  259. border: 1px solid #2d343d;
  260. border-radius: 6px;
  261. }
  262. .form-field {
  263. display: flex;
  264. flex-direction: column;
  265. gap: 4px;
  266. max-width: 560px;
  267. }
  268. .form-field > label {
  269. font-size: 12px;
  270. color: #90a4ae;
  271. }
  272. .form-field input[type="text"],
  273. .form-field input[type="number"],
  274. .form-field select {
  275. font: inherit;
  276. padding: 5px 8px;
  277. border: 1px solid #4a5560;
  278. border-radius: 4px;
  279. background: #262c34;
  280. color: #e6e9ec;
  281. }
  282. .form-field input[type="text"].readonly,
  283. .form-field select.readonly {
  284. opacity: 0.7;
  285. }
  286. .form-boolean {
  287. display: flex;
  288. align-items: center;
  289. gap: 8px;
  290. font-size: 13px;
  291. cursor: pointer;
  292. }
  293. .form-section {
  294. border: 1px solid #2d343d;
  295. border-radius: 6px;
  296. padding: 8px 10px;
  297. display: flex;
  298. flex-direction: column;
  299. gap: 8px;
  300. margin: 0;
  301. background: #171b20;
  302. }
  303. .form-section legend {
  304. font-size: 12px;
  305. color: #90a4ae;
  306. text-transform: uppercase;
  307. letter-spacing: 0.06em;
  308. padding: 0 6px;
  309. }
  310. .form-section-body {
  311. display: flex;
  312. flex-direction: column;
  313. gap: 8px;
  314. }
  315. .form-array,
  316. .form-record {
  317. display: flex;
  318. flex-direction: column;
  319. gap: 6px;
  320. border: 1px solid #2d343d;
  321. border-radius: 6px;
  322. padding: 8px 10px;
  323. background: #171b20;
  324. }
  325. .form-array-header,
  326. .form-record-header,
  327. .form-union-header {
  328. display: flex;
  329. align-items: center;
  330. gap: 8px;
  331. }
  332. .form-array-label,
  333. .form-record-label,
  334. .form-union-label {
  335. font-size: 12px;
  336. color: #90a4ae;
  337. text-transform: uppercase;
  338. letter-spacing: 0.06em;
  339. flex: 1;
  340. }
  341. .form-array-list,
  342. .form-record-rows {
  343. display: flex;
  344. flex-direction: column;
  345. gap: 6px;
  346. }
  347. .form-array-item {
  348. display: flex;
  349. align-items: flex-start;
  350. gap: 8px;
  351. padding: 6px;
  352. border: 1px solid #2d343d;
  353. border-radius: 4px;
  354. background: #1c2127;
  355. }
  356. .form-array-item > input,
  357. .form-array-item > select {
  358. flex: 1;
  359. min-width: 0;
  360. }
  361. .form-array-item-body {
  362. flex: 1;
  363. min-width: 0;
  364. }
  365. .form-array-controls {
  366. display: flex;
  367. gap: 4px;
  368. flex: none;
  369. }
  370. .form-array-controls button {
  371. padding: 4px 8px;
  372. font-size: 12px;
  373. }
  374. .form-union {
  375. display: flex;
  376. flex-direction: column;
  377. gap: 6px;
  378. border: 1px solid #2d343d;
  379. border-radius: 6px;
  380. padding: 8px 10px;
  381. background: #171b20;
  382. }
  383. .form-union-body {
  384. display: flex;
  385. flex-direction: column;
  386. gap: 8px;
  387. }
  388. .form-branch-select {
  389. font: inherit;
  390. padding: 5px 8px;
  391. border: 1px solid #4a5560;
  392. border-radius: 4px;
  393. background: #262c34;
  394. color: #e6e9ec;
  395. }
  396. .form-record-row {
  397. display: flex;
  398. align-items: flex-start;
  399. gap: 8px;
  400. }
  401. .form-record-row > input {
  402. flex: 1;
  403. min-width: 0;
  404. font: inherit;
  405. padding: 5px 8px;
  406. border: 1px solid #4a5560;
  407. border-radius: 4px;
  408. background: #262c34;
  409. color: #e6e9ec;
  410. }
  411. .form-record-row > .form-record-value {
  412. flex: 2;
  413. min-width: 0;
  414. }
  415. #statusbar {
  416. padding: 6px 16px;
  417. background: #1f242b;
  418. border-top: 1px solid #2d343d;
  419. color: #7f8c99;
  420. font-size: 12px;
  421. }
  422. .status-error {
  423. color: #ef5350;
  424. }
  425. button:disabled {
  426. opacity: 0.5;
  427. cursor: default;
  428. }
  429. .map-editor {
  430. display: flex;
  431. flex-direction: column;
  432. gap: 10px;
  433. flex: 1;
  434. min-height: 0;
  435. }
  436. .map-toolbar {
  437. display: flex;
  438. align-items: center;
  439. gap: 10px;
  440. flex-wrap: wrap;
  441. }
  442. .map-toolbar h3 {
  443. margin: 0;
  444. }
  445. .map-path {
  446. color: #7f8c99;
  447. font-size: 12px;
  448. flex: 1;
  449. min-width: 0;
  450. overflow: hidden;
  451. text-overflow: ellipsis;
  452. white-space: nowrap;
  453. }
  454. .map-tools {
  455. display: flex;
  456. gap: 6px;
  457. }
  458. .map-tool-button {
  459. padding: 5px 12px;
  460. font-size: 12px;
  461. }
  462. .map-tool-button.selected {
  463. background: #2e7d32;
  464. border-color: #66bb6a;
  465. }
  466. .map-body {
  467. display: flex;
  468. gap: 12px;
  469. flex: 1;
  470. min-height: 0;
  471. }
  472. .map-palette {
  473. width: 180px;
  474. flex: none;
  475. overflow: auto;
  476. display: flex;
  477. flex-direction: column;
  478. gap: 8px;
  479. padding: 10px;
  480. background: #1c2127;
  481. border: 1px solid #2d343d;
  482. border-radius: 6px;
  483. }
  484. .palette-list {
  485. display: flex;
  486. flex-direction: column;
  487. gap: 4px;
  488. }
  489. .palette-swatch {
  490. display: flex;
  491. align-items: center;
  492. gap: 8px;
  493. padding: 5px 8px;
  494. text-align: left;
  495. }
  496. .palette-swatch.selected {
  497. border-color: #66bb6a;
  498. background: #2e7d32;
  499. }
  500. .swatch-chip {
  501. width: 22px;
  502. height: 22px;
  503. border-radius: 3px;
  504. border: 1px solid rgba(0, 0, 0, 0.4);
  505. flex: none;
  506. }
  507. .swatch-label {
  508. font-size: 12px;
  509. overflow: hidden;
  510. text-overflow: ellipsis;
  511. }
  512. .add-tile-form {
  513. display: flex;
  514. gap: 6px;
  515. }
  516. .add-tile-form input {
  517. flex: 1;
  518. min-width: 0;
  519. font: inherit;
  520. padding: 5px 8px;
  521. border: 1px solid #4a5560;
  522. border-radius: 4px;
  523. background: #262c34;
  524. color: #e6e9ec;
  525. }
  526. .map-canvas-wrap {
  527. flex: 1;
  528. min-width: 0;
  529. overflow: auto;
  530. background: #111417;
  531. border: 1px solid #2d343d;
  532. border-radius: 6px;
  533. padding: 8px;
  534. }
  535. #map-canvas,
  536. .map-canvas-wrap canvas {
  537. display: block;
  538. image-rendering: pixelated;
  539. cursor: crosshair;
  540. }
  541. .scene-editor {
  542. display: flex;
  543. flex-direction: column;
  544. gap: 10px;
  545. flex: 1;
  546. min-height: 0;
  547. }
  548. .scene-toolbar {
  549. display: flex;
  550. align-items: center;
  551. gap: 10px;
  552. flex-wrap: wrap;
  553. }
  554. .scene-toolbar h3 {
  555. margin: 0;
  556. }
  557. .scene-path {
  558. color: #7f8c99;
  559. font-size: 12px;
  560. flex: 1;
  561. min-width: 0;
  562. overflow: hidden;
  563. text-overflow: ellipsis;
  564. white-space: nowrap;
  565. }
  566. .scene-mode-toggle {
  567. display: flex;
  568. gap: 6px;
  569. }
  570. .scene-mode-button {
  571. padding: 5px 12px;
  572. font-size: 12px;
  573. }
  574. .scene-mode-button.selected {
  575. background: #2e7d32;
  576. border-color: #66bb6a;
  577. }
  578. .scene-body {
  579. display: flex;
  580. gap: 12px;
  581. flex: 1;
  582. min-height: 0;
  583. }
  584. .scene-palette {
  585. width: 180px;
  586. flex: none;
  587. overflow: auto;
  588. display: flex;
  589. flex-direction: column;
  590. gap: 8px;
  591. padding: 10px;
  592. background: #1c2127;
  593. border: 1px solid #2d343d;
  594. border-radius: 6px;
  595. }
  596. .scene-palette-section {
  597. margin: 6px 0 0;
  598. font-size: 11px;
  599. color: #90a4ae;
  600. text-transform: uppercase;
  601. letter-spacing: 0.06em;
  602. }
  603. .scene-palette-list {
  604. display: flex;
  605. flex-direction: column;
  606. gap: 4px;
  607. }
  608. .scene-palette-item {
  609. display: flex;
  610. align-items: center;
  611. justify-content: space-between;
  612. gap: 8px;
  613. padding: 5px 8px;
  614. text-align: left;
  615. }
  616. .scene-palette-item.selected {
  617. border-color: #66bb6a;
  618. background: #2e7d32;
  619. }
  620. .scene-palette-badge {
  621. color: #90a4ae;
  622. font-size: 11px;
  623. font-variant-numeric: tabular-nums;
  624. flex: none;
  625. }
  626. .scene-npc-form {
  627. display: flex;
  628. flex-direction: column;
  629. gap: 6px;
  630. }
  631. .scene-npc-form input {
  632. font: inherit;
  633. padding: 5px 8px;
  634. border: 1px solid #4a5560;
  635. border-radius: 4px;
  636. background: #262c34;
  637. color: #e6e9ec;
  638. }
  639. .scene-main {
  640. flex: 1;
  641. min-width: 0;
  642. display: flex;
  643. flex-direction: column;
  644. gap: 8px;
  645. }
  646. .scene-entity-list {
  647. border: 1px solid #2d343d;
  648. border-radius: 6px;
  649. background: #1c2127;
  650. padding: 8px 10px;
  651. max-height: 180px;
  652. overflow: auto;
  653. display: flex;
  654. flex-direction: column;
  655. gap: 6px;
  656. }
  657. .scene-entity-list h4 {
  658. margin: 0;
  659. font-size: 11px;
  660. color: #90a4ae;
  661. text-transform: uppercase;
  662. letter-spacing: 0.06em;
  663. }
  664. .scene-entity-rows {
  665. display: flex;
  666. flex-direction: column;
  667. gap: 3px;
  668. }
  669. .scene-entity-row {
  670. display: flex;
  671. align-items: center;
  672. gap: 8px;
  673. padding: 4px 8px;
  674. border-radius: 4px;
  675. cursor: pointer;
  676. font-size: 12px;
  677. }
  678. .scene-entity-row:hover {
  679. background: #262c34;
  680. }
  681. .scene-entity-row.selected {
  682. background: #2e7d32;
  683. }
  684. .scene-entity-dot {
  685. width: 10px;
  686. height: 10px;
  687. border-radius: 50%;
  688. border: 1px solid rgba(0, 0, 0, 0.4);
  689. flex: none;
  690. }
  691. .scene-entity-coords {
  692. color: #7f8c99;
  693. font-variant-numeric: tabular-nums;
  694. margin-left: auto;
  695. }
  696. .scene-entity-delete {
  697. padding: 2px 7px;
  698. font-size: 12px;
  699. line-height: 1.1;
  700. flex: none;
  701. }
  702. #playtest {
  703. flex: 1;
  704. display: flex;
  705. flex-direction: column;
  706. min-height: 0;
  707. background: #0d1013;
  708. }
  709. #playtest-topbar {
  710. display: flex;
  711. align-items: center;
  712. gap: 14px;
  713. padding: 8px 16px;
  714. background: #1f242b;
  715. border-bottom: 1px solid #2d343d;
  716. }
  717. #playtest-title {
  718. font-weight: 600;
  719. color: #a5d6a7;
  720. }
  721. #playtest-status {
  722. color: #7f8c99;
  723. font-size: 12px;
  724. flex: 1;
  725. }
  726. #playtest-game {
  727. flex: 1;
  728. min-height: 0;
  729. position: relative;
  730. }
  731. #playtest-hud {
  732. display: flex;
  733. align-items: center;
  734. gap: 16px;
  735. padding: 6px 16px;
  736. background: #1f242b;
  737. border-top: 1px solid #2d343d;
  738. color: #e6e9ec;
  739. font-size: 12px;
  740. }
  741. #playtest-time {
  742. color: #a5d6a7;
  743. font-variant-numeric: tabular-nums;
  744. }
  745. #playtest-stats {
  746. color: #e6e9ec;
  747. flex: 1;
  748. overflow: hidden;
  749. text-overflow: ellipsis;
  750. white-space: nowrap;
  751. }
  752. #playtest-feedback {
  753. color: #8bc34a;
  754. min-height: 14px;
  755. }
  756. .dialog-backdrop {
  757. position: fixed;
  758. inset: 0;
  759. background: rgba(0, 0, 0, 0.5);
  760. display: flex;
  761. align-items: center;
  762. justify-content: center;
  763. z-index: 40;
  764. }
  765. .dialog {
  766. width: 520px;
  767. max-width: 92vw;
  768. max-height: 82vh;
  769. overflow: auto;
  770. background: #1c2127;
  771. border: 1px solid #2d343d;
  772. border-radius: 8px;
  773. padding: 18px;
  774. display: flex;
  775. flex-direction: column;
  776. gap: 12px;
  777. }
  778. .dialog h3 {
  779. margin: 0;
  780. }
  781. .pack-checks {
  782. display: flex;
  783. flex-direction: column;
  784. gap: 6px;
  785. }
  786. .dialog-actions {
  787. display: flex;
  788. gap: 10px;
  789. }
  790. #pack-result {
  791. white-space: pre-wrap;
  792. font-family: ui-monospace, monospace;
  793. font-size: 12px;
  794. color: #8bc34a;
  795. max-height: 180px;
  796. overflow: auto;
  797. border: 1px solid #2d343d;
  798. border-radius: 4px;
  799. padding: 8px;
  800. background: #171b20;
  801. margin: 0;
  802. }
  803. #pack-result.status-error {
  804. color: #ef5350;
  805. }
  806. </style>
  807. </head>
  808. <body>
  809. <div id="app">
  810. <section id="home" class="screen">
  811. <h1>nEngine Editor</h1>
  812. <p class="muted">Create or open an nEngine project — a folder with <code>content/</code> (and optional <code>mods/</code>).</p>
  813. <div id="home-actions">
  814. <button id="btn-open" type="button" class="primary">Open project…</button>
  815. <button id="btn-new" type="button">New project…</button>
  816. </div>
  817. <h2>Recent projects</h2>
  818. <ul id="recent-list"></ul>
  819. <p id="home-error"></p>
  820. </section>
  821. <section id="editor" class="screen hidden">
  822. <header id="topbar">
  823. <span id="project-name"></span>
  824. <span id="project-path"></span>
  825. <span id="mcp-url" title="Embedded MCP endpoint — paste into your AI tool"></span>
  826. <button id="btn-mcp-copy" type="button" disabled>Copy MCP URL</button>
  827. <button id="btn-package" type="button">Package</button>
  828. <button id="btn-play" type="button" class="primary">Play</button>
  829. <button id="btn-close" type="button">Close project</button>
  830. </header>
  831. <div id="workspace">
  832. <aside id="content-browser">
  833. <h3>Content</h3>
  834. <ul id="content-list"></ul>
  835. </aside>
  836. <main id="editor-panel">
  837. <h3>Editor</h3>
  838. <p class="placeholder">Select a content kind from the sidebar. Maps open the visual tile editor.</p>
  839. </main>
  840. </div>
  841. <div id="statusbar">
  842. <span id="status"></span>
  843. </div>
  844. </section>
  845. <section id="playtest" class="screen hidden">
  846. <header id="playtest-topbar">
  847. <span id="playtest-title">Playtest</span>
  848. <span id="playtest-status"></span>
  849. <button id="btn-playtest-exit" type="button">Exit</button>
  850. </header>
  851. <div id="playtest-game"></div>
  852. <div id="playtest-hud">
  853. <span id="playtest-time"></span>
  854. <span id="playtest-stats"></span>
  855. <span id="playtest-feedback"></span>
  856. </div>
  857. </section>
  858. <section id="pack-dialog" class="hidden">
  859. <div class="dialog-backdrop">
  860. <div class="dialog">
  861. <h3>Package</h3>
  862. <p class="muted">Run the nengine-pack pipeline on this project: content → bundle.json + static site, plus optional desktop app and installer config. Fields pre-fill from project.yaml and are saved back on run.</p>
  863. <label class="form-field">Product name<input id="pack-name" type="text"></label>
  864. <label class="form-field">Icon path<input id="pack-icon" type="text" placeholder="icon.png (stored for future use — v1 ships the default Electron icon)"></label>
  865. <div class="pack-checks">
  866. <label class="form-boolean"><input id="pack-desktop" type="checkbox">Desktop app (Electron shell)</label>
  867. <label class="form-boolean"><input id="pack-installer" type="checkbox">Installer config (electron-builder)</label>
  868. <label class="form-boolean"><input id="pack-mods" type="checkbox">Include Mods (<code>mods/</code>)</label>
  869. <label class="form-boolean"><input id="pack-split" type="checkbox">Split assets into <code>nengine-assets/</code></label>
  870. </div>
  871. <label class="form-field">Output directory<input id="pack-outdir" type="text"></label>
  872. <pre id="pack-result"></pre>
  873. <div class="dialog-actions">
  874. <button id="btn-pack-run" type="button" class="primary">Run package</button>
  875. <button id="btn-pack-close" type="button">Close</button>
  876. </div>
  877. </div>
  878. </div>
  879. </section>
  880. </div>
  881. <script type="module" src="/src/renderer/main.ts"></script>
  882. </body>
  883. </html>