From a9870aca5d776ee6b90147ff727b8c69affae43b Mon Sep 17 00:00:00 2001 From: Kyle Florence Date: Fri, 8 May 2026 18:01:55 -0700 Subject: [PATCH 1/3] Editor play URL and various other bug fixes. Fixes #125 --- src/components/dialog.js | 2 +- src/components/editor.js | 4 ++- src/components/game.js | 6 ++--- src/components/modifier.js | 2 +- src/components/modifiers/puzzle.js | 5 ++++ src/components/puzzle.js | 21 ++++++++++++---- src/index.html | 9 ++++++- src/puzzles/index.js | 2 +- src/styles.css | 39 ++++++++++++++++++------------ 9 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/components/dialog.js b/src/components/dialog.js index ae7a7cf..a733ca7 100644 --- a/src/components/dialog.js +++ b/src/components/dialog.js @@ -13,7 +13,7 @@ document.querySelectorAll('[data-dialog]').forEach((target) => { const close = dialog.querySelector('header button') close.addEventListener('click', async () => { - const element = document.getElementById(dialog.dataset.from) + const element = document.getElementById(dialog.dataset.from) ?? title const direction = element.id === title.id ? 'right' : 'left' delete dialog.dataset.from diff --git a/src/components/editor.js b/src/components/editor.js index 9b3fd31..49efcf0 100644 --- a/src/components/editor.js +++ b/src/components/editor.js @@ -475,7 +475,9 @@ export class Editor { } #updatePlayUrl () { - elements.play.firstElementChild.setAttribute('href', this.#puzzle.getShareUrl(State.ContextKeys.Play)) + elements.play.firstElementChild.setAttribute( + 'href', + this.#puzzle.getShareUrl(State.ContextKeys.Play, true)) } static mark (center, width) { diff --git a/src/components/game.js b/src/components/game.js index 726e506..1a51585 100644 --- a/src/components/game.js +++ b/src/components/game.js @@ -23,8 +23,8 @@ const elements = Object.freeze({ editPuzzles: document.getElementById('edit-puzzles'), play: document.getElementById('title-play'), playLoad: document.getElementById('play-custom-load'), - playProfile: document.getElementById('play-profile'), playPuzzles: document.getElementById('play-puzzles'), + profile: document.querySelectorAll('.current-profile-name'), quit: document.getElementById('title-quit'), screen: document.getElementById('screen'), select: document.getElementById('select'), @@ -38,7 +38,7 @@ export class Game { #eventListeners = new EventListeners({ context: this }) constructor () { - elements.playProfile.textContent = Storage.Profile.get().name + elements.profile.forEach((element) => { element.textContent = Storage.Profile.get().name }) this.puzzle = new Puzzle() this.editor = new Editor(this.puzzle) @@ -180,7 +180,7 @@ export class Game { async #onProfileUpdate (event) { this.#teardown() Storage.Profiles.set(event.detail.id) - elements.playProfile.textContent = Storage.Profile.get().name + elements.profile.forEach((element) => { element.textContent = Storage.Profile.get().name }) Game.updatePuzzles() } diff --git a/src/components/modifier.js b/src/components/modifier.js index 9ec2753..e2ab897 100644 --- a/src/components/modifier.js +++ b/src/components/modifier.js @@ -159,7 +159,7 @@ export class Modifier extends Stateful { this.#down = false } - onTap (event, detail) { + onTap (event, detail = {}) { this.dispatchEvent(Modifier.Events.Invoked, detail) } diff --git a/src/components/modifiers/puzzle.js b/src/components/modifiers/puzzle.js index b1c56d7..cab5da2 100644 --- a/src/components/modifiers/puzzle.js +++ b/src/components/modifiers/puzzle.js @@ -45,6 +45,11 @@ export class PuzzleModifier extends Modifier { await puzzle.select(state.id, { animations: [Puzzle.Animations.SlideLeft] }) } + onTap (event, detail) { + // Invoking this modifier does not result in a move + super.onTap(event, { addMove: false }) + } + static schema () { const imports = Puzzles.imports() return Object.freeze(merge([ diff --git a/src/components/puzzle.js b/src/components/puzzle.js index bafeebc..1153f20 100644 --- a/src/components/puzzle.js +++ b/src/components/puzzle.js @@ -179,15 +179,16 @@ export class Puzzle { return this.#interact.getProjectPoint(point) } - getShareUrl (context = State.getContext()) { + getShareUrl (context = State.getContext(), clone = false) { // Electron runs on localhost but should use the production web URL const shareUrl = new URL(process.env.TARGET === 'electron' ? baseUrl : url) shareUrl.search = '' shareUrl.searchParams.append(context, '') - const state = this.state.getConfig() + const state = clone ? this.state.clone() : this.state + const config = state.getConfig() // Update the imports using data from local cache - State.resolveImports(state, this.state.getCurrent()) - shareUrl.hash = ['', State.getId(), this.state.encode(state)].join('/') + State.resolveImports(config, state.getCurrent()) + shareUrl.hash = ['', State.getId(), state.encode(config)].join('/') return shareUrl.toString() } @@ -663,7 +664,9 @@ export class Puzzle { .sort((beam) => tile.items.some((item) => item === beam) ? -1 : 0) .forEach((beam) => beam.onModifierInvoked(event, this)) - this.state.addMove(event.type, tile, modifier, this.selectedTile) + if (event.detail.addMove !== false) { + this.state.addMove(event.type, tile, modifier, this.selectedTile) + } setTimeout(async () => { this.updateState() @@ -841,6 +844,14 @@ export class Puzzle { Game.updatePuzzles([State.ContextKeys.Play]) document.body.classList.add(Puzzle.Events.Loaded) + + document.querySelectorAll('.group').forEach((element) => { + // Fixes .group:empty not updating properly in Safari + // This bug is marked as resolved but seems to still be manifesting + // https://bugs.webkit.org/show_bug.cgi?id=26570 + element.style.display = 'initial' + element.style.display = '' + }) } async #undo () { diff --git a/src/index.html b/src/index.html index 44ef70d..c93fc08 100644 --- a/src/index.html +++ b/src/index.html @@ -110,7 +110,7 @@

Play

Puzzles

Load a puzzle by tapping on its name in the list below. Puzzles which are greyed out have not been unlocked yet.

-

Using profile: default (you can change this on the settings screen)

+

Using profile: default (you can change this on the settings screen)

@@ -462,6 +462,13 @@

Edit

Puzzles +

+ Use the puzzle editor to create your own custom puzzles. To start a new puzzle, click the button below. + You can test your puzzle by tapping on the play () icon in the editor screen. + You can share your puzzle with others by copying the play URL, or by tapping on the share icon after opening + your puzzle via the play URL. +

+

Using profile: default (you can change this on the settings screen)

    diff --git a/src/puzzles/index.js b/src/puzzles/index.js index 76e89e4..711eca2 100644 --- a/src/puzzles/index.js +++ b/src/puzzles/index.js @@ -70,7 +70,7 @@ export class Puzzles { div.append(left) const right = document.createElement('span') - right.classList.add('flex-right') + right.classList.add('flex-right', 'icons') if (custom) { const remove = document.createElement('i') diff --git a/src/styles.css b/src/styles.css index f94aee2..59a6050 100644 --- a/src/styles.css +++ b/src/styles.css @@ -589,6 +589,7 @@ dialog ul { aspect-ratio: 1 / 1; color: #000; filter: drop-shadow(0 0.25em 0.25em #666); + min-height: 240px; min-width: 240px; margin-bottom: 2em; max-width: 480px; @@ -610,10 +611,6 @@ dialog ul { } } - p { - margin: 0; - } - textarea { border: 1px solid #aaa; border-radius: 0.5em; @@ -623,19 +620,8 @@ dialog ul { padding: 0.5em; width: 100%; } - - #play-profile-wrapper { - border-top: 1px solid #ddd; - margin-top: 1em; - padding-top: 1em; - } } -#play-profile { - font-weight: bold; -} - - #play-custom-configuration-error { background-color: #dc3545; border: 1px #dc3545 solid; @@ -893,6 +879,29 @@ dialog ul { margin: 0 0 0 1.5em; padding: 0; } + + .flex-left, + .flex-right { + flex: auto; + } + + .icons { + margin-left: 1em; + } +} + +.current-profile { + border-top: 1px solid #ddd !important; + margin-top: 1em; + padding-top: 1em; +} + +.current-profile-name { + font-weight: bold; +} + +.edit .puzzles li .status { + display: none; } /* ------------------------------------------------------------------------------------------------------------------ */ From 512009d08dbd60da6ff1d6529cf5cc18f8d04869 Mon Sep 17 00:00:00 2001 From: Kyle Florence Date: Fri, 8 May 2026 18:02:09 -0700 Subject: [PATCH 2/3] Bump package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 76c4820..91349c7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "beaming", "author": "Kyle Florence", "description": "A browser-based puzzle game that involves directing beams through a hexagonal grid.", - "version": "0.4.2", + "version": "0.4.3", "license": "CC BY-NC 4.0", "main": "src/electron/main.js", "type": "module", From 3b47f411868dd2d8351443cf06825fe5e08fbe93 Mon Sep 17 00:00:00 2001 From: Kyle Florence Date: Fri, 8 May 2026 18:08:43 -0700 Subject: [PATCH 3/3] Remove unnecessary important --- src/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles.css b/src/styles.css index 59a6050..f96a49b 100644 --- a/src/styles.css +++ b/src/styles.css @@ -891,7 +891,7 @@ dialog ul { } .current-profile { - border-top: 1px solid #ddd !important; + border-top: 1px solid #ddd; margin-top: 1em; padding-top: 1em; }