URL скопирован в буфер обмена!

Как сделать интерактивный поиск слов (фивлорд)на Tilda?

С помощью этой модификации можно сделать филворд в Zero Block. Пользователь выделяет слова в сетке букв мышью или свайпом, а найденные слова отмечаются в списке. Поддерживает разные направления поиска и сохранение прогресса. Дополнительно можно добавить кнопку очистки, конфетти, открытие попапа или переход по ссылке после завершения игры.

Модификация работает с включенным Autoscale в блоках
Модификация работает c Zero Block и стандартными блоками
Номер модификации в библиотеке TiCode

Генератор кода

Тип выделения
Класс сетки
Класс слов
Цвет фона при выделении
Цвет линии при выделении
Цвет фона при совпадении
Цвет линии при совпадении
Кеширование результата, дней (0 — выключено)
Конфетти
Результат
Войдите в аккаунт чтобы получить доступ к генератору кода
Этот генератор кода доступен только тем кто оплатил подписку
<!--TICODE--><!-- Библиотека модификаций для Тильда https://ticode.dev --> <!--TCD146--><style> .ti-wordsearch,.ti-wordsearch .tn-atom{overflow:visible!important} .ti-wordsearch .tc-board{position:relative;display:inline-grid;grid-template-columns:repeat(var(--tc-cols),var(--tc-cell));width:max-content;isolation:isolate;vertical-align:top;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;touch-action:none;cursor:crosshair;--tc-cell:1.55em} .ti-wordsearch .tc-cell{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;width:var(--tc-cell);height:var(--tc-cell);padding:0;margin:0;border-radius:0!important;box-sizing:border-box;line-height:1;letter-spacing:0} .ti-wordsearch .tc-cell.tc-found{background:#CAE6D6} .ti-wordsearch .tc-cell.tc-selecting{background:#CFE4FF} .ti-wordsearch .tc-lines{position:absolute;inset:0;z-index:2;width:100%;height:100%;overflow:visible;pointer-events:none} .ti-wordsearch .tc-board.tc-complete{cursor:default} .ti-word.tc-word-found .tn-atom,.ti-word.tc-word-found .tn-atom *{color:#239653!important;-webkit-text-fill-color:#239653!important;text-decoration-line:line-through!important;text-decoration-color:#239653!important;text-decoration-thickness:2px!important} .tc-clear{cursor:pointer} </style> <script> (() => { const tcdConfettiEnabled = false; function ticodeConfetti() { const tcdCanvas = document.createElement('canvas'); tcdCanvas.setAttribute('aria-hidden', 'true'); tcdCanvas.style.cssText = 'position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:2147483647;'; document.body.appendChild(tcdCanvas); const tcdContext = tcdCanvas.getContext('2d'); if (!tcdContext) { tcdCanvas.remove(); return () => {}; } const tiWidth = innerWidth; const tiHeight = innerHeight; const tiRatio = Math.min(devicePixelRatio || 1, 2); tcdCanvas.width = Math.ceil(tiWidth * tiRatio); tcdCanvas.height = Math.ceil(tiHeight * tiRatio); tcdContext.scale(tiRatio, tiRatio); const tiColors = ['#2684ff', '#239653', '#ffd166', '#ef476f', '#a78bfa']; const tiPieces = Array.from({length: 160}, () => ({ tiX: Math.random() * tiWidth, tiY: -20 - Math.random() * tiHeight * .55, tiVx: (Math.random() - .5) * 140, tiVy: 160 + Math.random() * 230, tiAngle: Math.random() * Math.PI, tiSpin: (Math.random() - .5) * 9, tiSize: 5 + Math.random() * 7, tiColor: tiColors[Math.floor(Math.random() * tiColors.length)] })); const tiStart = performance.now(); let tiPrevious = tiStart; let tiAnimation = null; function ticodeStop() { cancelAnimationFrame(tiAnimation); tcdCanvas.remove(); } function ticodeAnimate(tiNow) { const tiElapsed = tiNow - tiStart; const tiDelta = Math.min((tiNow - tiPrevious) / 1000, .04); tiPrevious = tiNow; tcdContext.clearRect(0, 0, tiWidth, tiHeight); tcdContext.globalAlpha = Math.max(0, Math.min(1, (3200 - tiElapsed) / 600)); tiPieces.forEach(tiPiece => { tiPiece.tiX += tiPiece.tiVx * tiDelta; tiPiece.tiY += tiPiece.tiVy * tiDelta; tiPiece.tiVy += 90 * tiDelta; tiPiece.tiAngle += tiPiece.tiSpin * tiDelta; tcdContext.save(); tcdContext.translate(tiPiece.tiX, tiPiece.tiY); tcdContext.rotate(tiPiece.tiAngle); tcdContext.fillStyle = tiPiece.tiColor; tcdContext.fillRect(-tiPiece.tiSize / 2, -tiPiece.tiSize / 4, tiPiece.tiSize, tiPiece.tiSize / 2); tcdContext.restore(); }); if (tiElapsed < 3200) tiAnimation = requestAnimationFrame(ticodeAnimate); else ticodeStop(); } tiAnimation = requestAnimationFrame(ticodeAnimate); return ticodeStop; } const tiHorizontal = true; const tiVertical = false; const tiFree = false; const tiAllowReverse = false; const tcGames = []; const tiNormalize = tcText => tcText.normalize('NFC').toUpperCase().replace(/\s+/gu, ''); function ticodeInit() { document.querySelectorAll('.ti-wordsearch').forEach((tcdFrame, tcIndex) => { if (tcdFrame.dataset.tcReady) return; const tcdAtom = tcdFrame.querySelector('.tn-atom'); const tcdRecord = tcdFrame.closest('.t-rec'); if (!tcdAtom || !tcdRecord) return; const tiRows = tcdAtom.innerText.split(/\r?\n/).map(tiNormalize).filter(Boolean).map(tcRow => Array.from(tcRow)); if (!tiRows.length) return; const tiColumns = tiRows[0].length; if (!tiRows.every(tcRow => tcRow.length === tiColumns)) return; const tiWords = Array.from(tcdRecord.querySelectorAll('.ti-word')).map(tcElement => ({ tcElement, tcText: tiNormalize((tcElement.querySelector('.tn-atom') || tcElement).innerText), tcFound: false })).filter(tcWord => tcWord.tcText); if (!tiWords.length) return; tcdFrame.dataset.tcReady = 'true'; const tcSignature = JSON.stringify([tiRows, tiWords.map(tcWord => tcWord.tcText), tiHorizontal, tiVertical, tiFree, tiAllowReverse]); const tcKey = 'tc-wordsearch-v2:' + location.pathname + ':' + (tcdRecord.id || '') + ':' + (tcdFrame.dataset.elemId || tcIndex); const tcdBoard = document.createElement('div'); tcdBoard.className = 'tc-board'; tcdBoard.style.setProperty('--tc-cols', tiColumns); tcdBoard.setAttribute('aria-label', 'Поле поиска слов'); const tiCells = []; tiRows.forEach((tcRow, tcR) => tcRow.forEach((tcLetter, tcC) => { const tcElement = document.createElement('span'); tcElement.className = 'tc-cell'; tcElement.textContent = tcLetter; tcdBoard.appendChild(tcElement); tiCells.push({tcElement, tcLetter, tcR, tcC, tcId: tiCells.length}); })); const tcdSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); tcdSvg.classList.add('tc-lines'); tcdSvg.setAttribute('aria-hidden', 'true'); tcdSvg.setAttribute('viewBox', `0 0 ${tiColumns} ${tiRows.length}`); tcdSvg.setAttribute('preserveAspectRatio', 'none'); tcdBoard.appendChild(tcdSvg); tcdAtom.replaceChildren(tcdBoard); const tiUsedCells = new Set(); let tcFoundPaths = []; let tcSelected = []; let tcStartCell = null; let tcPointerId = null; let tcPreviousPoint = null; let tcComplete = false; let tcExpires = null; let tiFinishTimer = null; let tiStopConfetti = null; const tcCacheEnabled = false; const tcCacheDays = 0; function ticodeRemoveCache() { try { localStorage.removeItem(tcKey); } catch (tcError) {} } function ticodeSave() { if (!tcCacheEnabled) return; if (!tcExpires || tcExpires <= Date.now()) tcExpires = Date.now() + tcCacheDays * 86400000; try { localStorage.setItem(tcKey, JSON.stringify({ tcSignature, tcExpires, tcPaths: tcFoundPaths.map(tcPath => tcPath.map(tcCell => tcCell.tcId)) })); } catch (tcError) {} } function tcMatches(tcPath) { const tcText = tcPath.map(tcCell => tcCell.tcLetter).join(''); const tcReverse = Array.from(tcText).reverse().join(''); return tiWords.filter(tcWord => !tcWord.tcFound && (tcWord.tcText === tcText || (tiAllowReverse && tcWord.tcText === tcReverse))); } function tcAccept(tcPath) { if (new Set(tcPath).size !== tcPath.length || tcPath.some(tcCell => tiUsedCells.has(tcCell.tcId))) return false; const tcMatched = tcMatches(tcPath); if (!tcPath.length || !tcMatched.length) return false; tcFoundPaths.push([...tcPath]); tcPath.forEach(tcCell => { tiUsedCells.add(tcCell.tcId); tcCell.tcElement.classList.add('tc-found'); }); tcMatched.forEach(tcWord => { tcWord.tcFound = true; tcWord.tcElement.classList.add('tc-word-found'); }); tcComplete = tiWords.every(tcWord => tcWord.tcFound); tcdBoard.classList.toggle('tc-complete', tcComplete); return true; } function ticodeRestore() { if (!tcCacheEnabled) { ticodeRemoveCache(); return; } try { const tcSaved = JSON.parse(localStorage.getItem(tcKey) || 'null'); if (!tcSaved) return; if (tcSaved.tcSignature !== tcSignature || !Number.isFinite(tcSaved.tcExpires) || tcSaved.tcExpires <= Date.now() || !Array.isArray(tcSaved.tcPaths)) { ticodeRemoveCache(); return; } tcExpires = tcSaved.tcExpires; tcSaved.tcPaths.forEach(tcIds => { if (!Array.isArray(tcIds) || !tcIds.length || !tcIds.every(tcId => Number.isInteger(tcId) && tcId >= 0 && tcId < tiCells.length)) return; const tcPath = tcIds.map(tcId => tiCells[tcId]); const tcValid = tcPath.every((tcCell, tcI) => { if (!tcI) return true; const tcPrev = tcPath[tcI - 1]; const tcDx = tcCell.tcC - tcPrev.tcC; const tcDy = tcCell.tcR - tcPrev.tcR; if (Math.abs(tcDx) + Math.abs(tcDy) !== 1) return false; if (tiFree) return true; return (tiHorizontal && tcPath.every(tcItem => tcItem.tcR === tcPath[0].tcR)) || (tiVertical && tcPath.every(tcItem => tcItem.tcC === tcPath[0].tcC)); }); if (tcValid) tcAccept(tcPath); }); } catch (tcError) { ticodeRemoveCache(); } } function tcPointAt(tcEvent) { const tcRect = tcdBoard.getBoundingClientRect(); if (!tcRect.width || !tcRect.height) return null; return {tcX: (tcEvent.clientX - tcRect.left) / tcRect.width * tiColumns, tcY: (tcEvent.clientY - tcRect.top) / tcRect.height * tiRows.length}; } function tcCellAt(tcPoint) { if (!tcPoint || tcPoint.tcX < 0 || tcPoint.tcX >= tiColumns || tcPoint.tcY < 0 || tcPoint.tcY >= tiRows.length) return null; return tiCells[Math.floor(tcPoint.tcY) * tiColumns + Math.floor(tcPoint.tcX)]; } function tcStraightPath(tcEnd) { if (!tcEnd) return []; const tcDx = tcEnd.tcC - tcStartCell.tcC; const tcDy = tcEnd.tcR - tcStartCell.tcR; if (!tcDx && !tcDy) return [tcStartCell]; if (!tcDy && tiHorizontal) return Array.from({length: Math.abs(tcDx) + 1}, (tcUnused, tcI) => tiCells[tcStartCell.tcR * tiColumns + tcStartCell.tcC + Math.sign(tcDx) * tcI]); if (!tcDx && tiVertical) return Array.from({length: Math.abs(tcDy) + 1}, (tcUnused, tcI) => tiCells[(tcStartCell.tcR + Math.sign(tcDy) * tcI) * tiColumns + tcStartCell.tcC]); return []; } function tcVisit(tcCell) { if (!tcCell || !tcSelected.length) return; const tcLast = tcSelected[tcSelected.length - 1]; if (Math.abs(tcCell.tcC - tcLast.tcC) + Math.abs(tcCell.tcR - tcLast.tcR) !== 1) return; if (tiUsedCells.has(tcCell.tcId)) return; const tiPreviousCell = tcSelected[tcSelected.length - 2]; if (tcCell === tiPreviousCell) tcSelected.pop(); else if (!tcSelected.includes(tcCell)) tcSelected.push(tcCell); } function tcTrace(tcFrom, tcTo) { if (!tcFrom || !tcTo) return; const tcDx = tcTo.tcX - tcFrom.tcX; const tcDy = tcTo.tcY - tcFrom.tcY; const tcCuts = [0, 1]; if (tcDx) for (let tcX = 0; tcX <= tiColumns; tcX++) { const tcT = (tcX - tcFrom.tcX) / tcDx; if (tcT > 0 && tcT < 1) tcCuts.push(tcT); } if (tcDy) for (let tcY = 0; tcY <= tiRows.length; tcY++) { const tcT = (tcY - tcFrom.tcY) / tcDy; if (tcT > 0 && tcT < 1) tcCuts.push(tcT); } tcCuts.sort((tcA, tcB) => tcA - tcB); for (let tcI = 0; tcI < tcCuts.length - 1; tcI++) { if (tcCuts[tcI + 1] - tcCuts[tcI] < 1e-9) continue; const tcT = (tcCuts[tcI] + tcCuts[tcI + 1]) / 2; tcVisit(tcCellAt({tcX: tcFrom.tcX + tcDx * tcT, tcY: tcFrom.tcY + tcDy * tcT})); } tcVisit(tcCellAt(tcTo)); } function ticodeLine(tcPath, tcColor) { if (tcPath.length < 2) return; const tcLineElement = document.createElementNS('http://www.w3.org/2000/svg', 'polyline'); tcLineElement.setAttribute('points', tcPath.map(tcCell => `${tcCell.tcC + .5},${tcCell.tcR + .5}`).join(' ')); tcLineElement.setAttribute('fill', 'none'); tcLineElement.setAttribute('stroke', tcColor); tcLineElement.setAttribute('stroke-width', '.085'); tcLineElement.setAttribute('stroke-linecap', 'butt'); tcLineElement.setAttribute('stroke-linejoin', 'miter'); tcdSvg.appendChild(tcLineElement); } function ticodeDraw() { tiCells.forEach(tcCell => tcCell.tcElement.classList.remove('tc-selecting')); tcSelected.forEach(tcCell => tcCell.tcElement.classList.add('tc-selecting')); tcdSvg.replaceChildren(); tcFoundPaths.forEach(tcPath => ticodeLine(tcPath, '#239653')); ticodeLine(tcSelected, '#2684ff'); } function tcUpdate(tcEvent) { const tcSamples = tcEvent.getCoalescedEvents?.(); const tcEvents = tcSamples?.length ? [...tcSamples, tcEvent] : [tcEvent]; tcEvents.forEach(tcSample => { const tcPoint = tcPointAt(tcSample); if (!tcPoint) return; if (tiFree) tcTrace(tcPreviousPoint, tcPoint); else { const tiCandidate = tcStraightPath(tcCellAt(tcPoint)); const tiBlocked = tiCandidate.findIndex(tcCell => tiUsedCells.has(tcCell.tcId)); tcSelected = tiBlocked < 0 ? tiCandidate : tiCandidate.slice(0, tiBlocked); } tcPreviousPoint = tcPoint; }); ticodeDraw(); } function tcRelease() { const tcReleased = tcPointerId; tcPointerId = null; tcStartCell = null; tcPreviousPoint = null; tcSelected = []; if (tcReleased !== null && tcdBoard.hasPointerCapture(tcReleased)) tcdBoard.releasePointerCapture(tcReleased); ticodeDraw(); } const tiFinishMode = 3; function ticodeFinishAction() { if (tiFinishMode === 2) { const tiRedirectUrl = ''; try { const tcUrl = new URL(tiRedirectUrl, location.href); if (['http:', 'https:'].includes(tcUrl.protocol)) location.assign(tcUrl.href); } catch (tcError) {} } else if (tiFinishMode === 1) { const tiPopupUrl = '#popup:tilda'; if (!tiPopupUrl.startsWith('#popup:')) return; const tcLink = document.createElement('a'); tcLink.href = tiPopupUrl; tcLink.tabIndex = -1; tcLink.setAttribute('aria-hidden', 'true'); tcLink.style.cssText = 'position:fixed;width:1px;height:1px;opacity:0;pointer-events:none;left:-9999px;'; document.body.appendChild(tcLink); tcLink.click(); setTimeout(() => tcLink.remove(), 1000); } } function ticodeFinish(tcEvent, tcCancelled) { if (tcEvent.pointerId !== tcPointerId) return; let tcAccepted = false; if (!tcCancelled) { tcUpdate(tcEvent); tcAccepted = tcAccept(tcSelected); if (tcAccepted) ticodeSave(); } tcRelease(); if (tcAccepted && tcComplete) { if (tcdConfettiEnabled) tiStopConfetti = ticodeConfetti(); if (tcdConfettiEnabled && tiFinishMode === 2) { tiFinishTimer = setTimeout(() => { tiFinishTimer = null; if (tcComplete) ticodeFinishAction(); }, 1800); } else ticodeFinishAction(); } } function ticodeReset() { clearTimeout(tiFinishTimer); tiFinishTimer = null; if (tiStopConfetti) tiStopConfetti(); tiStopConfetti = null; tcRelease(); tcFoundPaths = []; tiUsedCells.clear(); tcComplete = false; tcExpires = null; tcdBoard.classList.remove('tc-complete'); tiCells.forEach(tcCell => tcCell.tcElement.classList.remove('tc-found')); tiWords.forEach(tcWord => { tcWord.tcFound = false; tcWord.tcElement.classList.remove('tc-word-found'); }); ticodeRemoveCache(); ticodeDraw(); } tcdBoard.addEventListener('pointerdown', tcEvent => { if (tcComplete || tcPointerId !== null || !tcEvent.isPrimary || (tcEvent.pointerType === 'mouse' && tcEvent.button !== 0)) return; if (!tiFree && !tiHorizontal && !tiVertical) return; const tcPoint = tcPointAt(tcEvent); const tcCell = tcCellAt(tcPoint); if (!tcCell || tiUsedCells.has(tcCell.tcId)) return; tcEvent.preventDefault(); tcStartCell = tcCell; tcSelected = [tcCell]; tcPreviousPoint = tcPoint; tcPointerId = tcEvent.pointerId; tcdBoard.setPointerCapture(tcPointerId); ticodeDraw(); }); tcdBoard.addEventListener('pointermove', tcEvent => { if (tcEvent.pointerId !== tcPointerId) return; tcEvent.preventDefault(); tcUpdate(tcEvent); }); tcdBoard.addEventListener('pointerup', tcEvent => ticodeFinish(tcEvent, false)); tcdBoard.addEventListener('pointercancel', tcEvent => ticodeFinish(tcEvent, true)); tcdBoard.addEventListener('lostpointercapture', tcEvent => ticodeFinish(tcEvent, true)); tcdBoard.addEventListener('dragstart', tcEvent => tcEvent.preventDefault()); ticodeRestore(); ticodeDraw(); tcGames.push({ticodeReset}); }); } document.addEventListener('click', tcEvent => { if (!(tcEvent.target instanceof Element) || !tcEvent.target.closest('.tc-clear')) return; tcEvent.preventDefault(); tcGames.forEach(tcGame => tcGame.ticodeReset()); }); if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', ticodeInit); else ticodeInit(); window.addEventListener('load', ticodeInit); })(); </script> <script> (function TCDupdType() { const TildahtmlBlock = document.currentScript; if (!TildahtmlBlock) { return; } const recordElement = TildahtmlBlock.closest( ".r[data-record-type]" ); if (!recordElement) { return; } recordElement.setAttribute( "data-record-type", Math.random().toString(36).substring(2, 12) ); })(); </script>
КОПИРОВАТЬ КОД
1. Создаём в Zero Block текстовый элемент с сеткой букв и присваиваем ему класс ti-wordsearch. Строки размещаем друг под другом без пустых строк. Между буквами ставим один пробел. Во всех строках должно быть одинаковое количество букв.
Для создания сетки букв можно использовать онлайн-генераторы филвордов, например этот генератор

Чтобы добавить класс, нажимаем на элемент правой кнопкой мыши и выбираем из списка "Add CSS Class Name" и далее, справа в настройках указываем класс

Важно! В конце каждого ряда должен быть перенос на следующую строку через Enter. Чтобы увеличить расстояние между буквами, используйте настройку Spacing в Zero Block.

2. В этом же Zero Block создаём отдельные текстовые элементы со словами, которые нужно найти. Каждому элементу присваиваем класс ti-word. Слова должны присутствовать в сетке и соответствовать выбранному направлению поиска. Пересечения слов и диагональное выделение не поддерживаются.

3. Настраиваем поля генератора:
Тип выделения — выбираем поиск по горизонтали, вертикали, в обоих направлениях или свободное выделение. В свободном режиме слово может поворачивать: соседние буквы соединяются по горизонтали и вертикали
Класс сетки — класс текстового элемента с сеткой букв. По умолчанию ti-wordsearch
Класс слов — класс текстовых элементов со словами для поиска. По умолчанию ti-word
Цвет фона при выделении — фон букв, которые пользователь выделяет мышью или свайпом
Цвет линии при выделении — цвет линии, соединяющей выделяемые буквы
Цвет фона при совпадении — фон букв найденного слова
Цвет линии при совпадении — цвет линии найденного слова
Кеширование результата — количество дней хранения прогресса в браузере. Найденные слова восстановятся при повторном открытии страницы. Значение 0 отключает сохранение
Конфетти — включает праздничную анимацию после нахождения всех слов
Результат — действие после завершения игры: ничего, переход по ссылке или открытие попапа. Для перехода указываем адрес страницы. Для попапа указываем ссылку формата #popup:tilda. Важно! ссылка дял попап долнжа начится с #popup:

Кнопка очистки. При необходимости создаём кнопку в Zero Block и присваиваем ей класс tc-clear. Нажатие сбрасывает найденные слова, выделения и сохранённый прогресс всех игр на странице

4. Копируем код и вставляем HTML блок T123. Блок Т123 размещаем под блокам сетки
Ц В Е Т А Б Р И С О
О Н А С К У Д Е М Л
Н М А К Е Т О Р И С
А Д У Б О С Н Е К Р
Б Р Ш Р И Ф Т А К О
У С О Н Е Б А Д И М
П А Л И Т Р А К О С
К У М О С Е Н Д А Р
А Б Л О Г О Т И П С
Д Е Н А У К С О Р М
ЛОГОТИП
ПАЛИТРА
МАКЕТ
ШРИФТ
ЦВЕТ