{
  "tfsVersion": "1",
  "exportDate": "2026-05-25",
  "bloc": {
    "name": "Split Text",
    "w": 11,
    "h": 7,
    "rows": [
      {
        "btns": [
          {
            "label": "Characters",
            "jsx": "~/Documents/TFS/scripts/Split_Text_Lettres.jsx",
            "type": "script",
            "scriptMode": "file",
            "expressionProperty": "position",
            "expressionCode": "",
            "commandMode": "effect",
            "commandId": "",
            "commandName": "",
            "commandNameFr": "",
            "img": "~/Documents/TFS/img/Split-letters.svg",
            "hideLabel": true,
            "tooltip": "Split Text by Characters",
            "_file": {
              "filename": "Split_Text_Lettres.jsx",
              "encoding": "utf8",
              "content": "(function () {\n\n    var isFrenchAE = (app.isoLanguage && app.isoLanguage.toLowerCase().indexOf(\"fr\") === 0);\n    function t(fr, en) {\n        return isFrenchAE ? fr : en;\n    }\n\n    function isTextLayer(layer) {\n        try {\n            return layer && layer.property(\"ADBE Text Properties\") && layer.property(\"Source Text\");\n        } catch (e) {\n            return false;\n        }\n    }\n\n    function getSelectedTextLayers(comp) {\n        var layers = [];\n\n        for (var i = 0; i < comp.selectedLayers.length; i++) {\n            if (isTextLayer(comp.selectedLayers[i])) {\n                layers.push(comp.selectedLayers[i]);\n            }\n        }\n\n        return layers;\n    }\n\n    function getLayerPosition(layer) {\n        var tr = layer.property(\"Transform\");\n        var p = tr.property(\"Position\");\n\n        if (p.dimensionsSeparated) {\n            var z = 0;\n            try {\n                z = tr.property(\"Z Position\").value;\n            } catch (e) {}\n\n            return [\n                tr.property(\"X Position\").value,\n                tr.property(\"Y Position\").value,\n                z\n            ];\n        }\n\n        var v = p.value;\n        return [v[0], v[1], v.length > 2 ? v[2] : 0];\n    }\n\n    function setLayerPosition(layer, x, y, z) {\n        var tr = layer.property(\"Transform\");\n        var p = tr.property(\"Position\");\n\n        if (p.dimensionsSeparated) {\n            tr.property(\"X Position\").setValue(x);\n            tr.property(\"Y Position\").setValue(y);\n\n            try {\n                tr.property(\"Z Position\").setValue(z || 0);\n            } catch (e) {}\n\n        } else {\n            if (p.value.length > 2) {\n                p.setValue([x, y, z || 0]);\n            } else {\n                p.setValue([x, y]);\n            }\n        }\n    }\n\n    function cleanLayerName(txt, fallback) {\n        var name = String(txt)\n            .replace(/\\r\\n|\\r|\\n/g, \" \")\n            .replace(/^\\s+|\\s+$/g, \"\");\n\n        if (!name) name = fallback || \"Letter\";\n\n        return name;\n    }\n\n    function createTempController(textLayer) {\n        var comp = textLayer.containingComp;\n        var controller = comp.layers.addNull();\n\n        controller.name = \"TEMP_SPLIT_TEXT_CONTROLLER\";\n\n        var srcTr = textLayer.property(\"Transform\");\n        var dstTr = controller.property(\"Transform\");\n\n        try { dstTr.property(\"Anchor Point\").setValue(srcTr.property(\"Anchor Point\").value); } catch (e) {}\n        try { dstTr.property(\"Scale\").setValue(srcTr.property(\"Scale\").value); } catch (e) {}\n        try { dstTr.property(\"Rotation\").setValue(srcTr.property(\"Rotation\").value); } catch (e) {}\n        try { dstTr.property(\"Opacity\").setValue(srcTr.property(\"Opacity\").value); } catch (e) {}\n\n        try {\n            var xRot = srcTr.property(\"X Rotation\");\n            var yRot = srcTr.property(\"Y Rotation\");\n            var zRot = srcTr.property(\"Z Rotation\");\n\n            if (xRot) dstTr.property(\"X Rotation\").setValue(xRot.value);\n            if (yRot) dstTr.property(\"Y Rotation\").setValue(yRot.value);\n            if (zRot) dstTr.property(\"Z Rotation\").setValue(zRot.value);\n        } catch (e2) {}\n\n        var pos = getLayerPosition(textLayer);\n        setLayerPosition(controller, pos[0], pos[1], pos[2]);\n\n        controller.inPoint = textLayer.inPoint;\n        controller.outPoint = textLayer.outPoint;\n\n        try {\n            controller.moveBefore(textLayer);\n        } catch (e3) {}\n\n        return controller;\n    }\n\n    function makeMeasureLayer(textLayer) {\n        var measureLayer = textLayer.duplicate();\n\n        measureLayer.name = \"TEMP_MEASURE\";\n        measureLayer.enabled = true;\n\n        var textProps = measureLayer.property(\"ADBE Text Properties\");\n        var animators = textProps.property(\"ADBE Text Animators\");\n\n        var animator = animators.addProperty(\"ADBE Text Animator\");\n        animator.name = \"Measurement Isolator\";\n\n        var animatorProps = animator.property(\"ADBE Text Animator Properties\");\n        animatorProps.addProperty(\"ADBE Text Scale 3D\").setValue([0, 0, 100]);\n\n        var selectors = animator.property(\"ADBE Text Selectors\");\n        var rangeSelector = selectors.addProperty(\"ADBE Text Selector\");\n\n        var advancedProps = rangeSelector.property(\"ADBE Text Range Advanced\");\n        advancedProps.property(\"ADBE Text Range Units\").setValue(2);\n        advancedProps.property(\"ADBE Text Range Type2\").setValue(2);\n        advancedProps.property(\"ADBE Text Selector Mode\").setValue(2);\n        advancedProps.property(\"ADBE Text Selector Max Amount\").setValue(100);\n\n        rangeSelector.property(\"ADBE Text Index Start\").setValue(0);\n        rangeSelector.property(\"ADBE Text Index End\").setValue(1);\n\n        return {\n            layer: measureLayer,\n            offset: rangeSelector.property(\"ADBE Text Index Offset\")\n        };\n    }\n\n    function measureCharacters(textLayer, textContent) {\n        var positions = [];\n        var time = textLayer.containingComp.time;\n        var measure = makeMeasureLayer(textLayer);\n\n        var charIndex = 0;\n\n        for (var i = 0; i < textContent.length; i++) {\n            var character = textContent.charAt(i);\n\n            if (character === \" \" || character === \"\\r\" || character === \"\\n\" || character === \"\\t\") {\n                positions.push({\n                    character: character,\n                    isSpace: true\n                });\n            } else {\n                measure.offset.setValue(charIndex);\n\n                var bounds = measure.layer.sourceRectAtTime(time, false);\n\n                positions.push({\n                    character: character,\n                    centerX: bounds.left + bounds.width / 2,\n                    centerY: bounds.top + bounds.height / 2\n                });\n\n                charIndex++;\n            }\n        }\n\n        measure.layer.remove();\n\n        return positions;\n    }\n\n    function createCharacterLayers(textLayer, characters) {\n        var comp = textLayer.containingComp;\n        var time = comp.time;\n\n        var controller = createTempController(textLayer);\n        var createdLayers = [];\n\n        for (var i = 0; i < characters.length; i++) {\n            var data = characters[i];\n\n            if (data.isSpace) continue;\n\n            var character = data.character;\n            if (!character) continue;\n\n            try {\n                var newLayer = textLayer.duplicate();\n\n                var textProp = newLayer.property(\"Source Text\");\n                var textDoc = textProp.value;\n                textDoc.text = character;\n                textProp.setValue(textDoc);\n\n                newLayer.name = cleanLayerName(character, \"Letter\");\n\n                var bounds = newLayer.sourceRectAtTime(time, false);\n\n                var anchorX = bounds.left + bounds.width / 2;\n                var anchorY = bounds.top + bounds.height / 2;\n\n                newLayer.property(\"Transform\")\n                    .property(\"Anchor Point\")\n                    .setValue([anchorX, anchorY]);\n\n                newLayer.parent = controller;\n\n                setLayerPosition(newLayer, data.centerX, data.centerY, 0);\n\n                newLayer.opened = false;\n                createdLayers.push(newLayer);\n\n            } catch (err) {}\n        }\n\n        for (var r = createdLayers.length - 1; r >= 0; r--) {\n            try {\n                createdLayers[r].moveBefore(textLayer);\n            } catch (e) {}\n        }\n\n        for (var p = 0; p < createdLayers.length; p++) {\n            try {\n                createdLayers[p].parent = null;\n            } catch (e2) {}\n        }\n\n        try {\n            controller.remove();\n        } catch (e3) {}\n\n        textLayer.enabled = false;\n\n        return createdLayers.length;\n    }\n\n    function splitTextLayerByCharacters(textLayer) {\n        var textContent = textLayer.property(\"Source Text\").value.text;\n\n        if (!textContent || textContent.length === 0) {\n            return 0;\n        }\n\n        var characters = measureCharacters(textLayer, textContent);\n\n        return createCharacterLayers(textLayer, characters);\n    }\n\n    var comp = app.project.activeItem;\n\n    if (!(comp instanceof CompItem)) {\n        alert(t(\n        \"Veuillez ouvrir une composition.\",\n        \"Please open a composition.\"\n    ));\n        return;\n    }\n\n    var selectedTextLayers = getSelectedTextLayers(comp);\n\n    if (selectedTextLayers.length === 0) {\n        alert(t(\n            \"Veuillez sélectionner un calque texte.\",\n            \"Please select a text layer.\"\n        ));\n        return;\n    }\n\n    app.beginUndoGroup(\"Split Text - Characters\");\n\n    for (var i = 0; i < selectedTextLayers.length; i++) {\n        splitTextLayerByCharacters(selectedTextLayers[i]);\n    }\n\n    app.endUndoGroup();\n\n})();"
            },
            "_imgFile": {
              "filename": "Split-letters.svg",
              "encoding": "utf8",
              "content": "<svg width=\"29\" height=\"16\" viewBox=\"0 0 29 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"8\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect x=\"16\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"24\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect y=\"6\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect y=\"12\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"8\" y=\"6\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"8\" y=\"12\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect x=\"16\" y=\"6\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect x=\"16\" y=\"12\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"24\" y=\"6\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"24\" y=\"12\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n</svg>\n"
            }
          },
          {
            "label": "Words",
            "jsx": "~/Documents/TFS/scripts/Split_Text_Mots.jsx",
            "type": "script",
            "scriptMode": "file",
            "expressionProperty": "position",
            "expressionCode": "",
            "commandMode": "effect",
            "commandId": "",
            "commandName": "",
            "commandNameFr": "",
            "img": "~/Documents/TFS/img/Split-words.svg",
            "hideLabel": true,
            "tooltip": "Split Text by Words",
            "_file": {
              "filename": "Split_Text_Mots.jsx",
              "encoding": "utf8",
              "content": "(function () {\n\n    var isFrenchAE = (app.isoLanguage && app.isoLanguage.toLowerCase().indexOf(\"fr\") === 0);\n    function t(fr, en) {\n        return isFrenchAE ? fr : en;\n    }\n\n    function isTextLayer(layer) {\n        try {\n            return layer && layer.property(\"ADBE Text Properties\") && layer.property(\"Source Text\");\n        } catch (e) {\n            return false;\n        }\n    }\n\n    function getSelectedTextLayers(comp) {\n        var layers = [];\n\n        for (var i = 0; i < comp.selectedLayers.length; i++) {\n            if (isTextLayer(comp.selectedLayers[i])) {\n                layers.push(comp.selectedLayers[i]);\n            }\n        }\n\n        return layers;\n    }\n\n    function getLayerPosition(layer) {\n        var tr = layer.property(\"Transform\");\n        var p = tr.property(\"Position\");\n\n        if (p.dimensionsSeparated) {\n            var z = 0;\n\n            try {\n                z = tr.property(\"Z Position\").value;\n            } catch (e) {}\n\n            return [\n                tr.property(\"X Position\").value,\n                tr.property(\"Y Position\").value,\n                z\n            ];\n        }\n\n        var v = p.value;\n        return [v[0], v[1], v.length > 2 ? v[2] : 0];\n    }\n\n    function setLayerPosition(layer, x, y, z) {\n        var tr = layer.property(\"Transform\");\n        var p = tr.property(\"Position\");\n\n        if (p.dimensionsSeparated) {\n            tr.property(\"X Position\").setValue(x);\n            tr.property(\"Y Position\").setValue(y);\n\n            try {\n                tr.property(\"Z Position\").setValue(z || 0);\n            } catch (e) {}\n\n        } else {\n            if (p.value.length > 2) {\n                p.setValue([x, y, z || 0]);\n            } else {\n                p.setValue([x, y]);\n            }\n        }\n    }\n\n    function cleanLayerName(txt, fallback) {\n        var name = String(txt)\n            .replace(/\\r\\n|\\r|\\n/g, \" \")\n            .replace(/^\\s+|\\s+$/g, \"\");\n\n        if (!name) name = fallback || \"Word\";\n        if (name.length > 100) name = name.substr(0, 100);\n\n        return name;\n    }\n\n    function createTempController(textLayer) {\n        var comp = textLayer.containingComp;\n        var controller = comp.layers.addNull();\n\n        controller.name = \"TEMP_SPLIT_TEXT_CONTROLLER\";\n\n        var srcTr = textLayer.property(\"Transform\");\n        var dstTr = controller.property(\"Transform\");\n\n        try { dstTr.property(\"Anchor Point\").setValue(srcTr.property(\"Anchor Point\").value); } catch (e) {}\n        try { dstTr.property(\"Scale\").setValue(srcTr.property(\"Scale\").value); } catch (e) {}\n        try { dstTr.property(\"Rotation\").setValue(srcTr.property(\"Rotation\").value); } catch (e) {}\n        try { dstTr.property(\"Opacity\").setValue(srcTr.property(\"Opacity\").value); } catch (e) {}\n\n        try {\n            var xRot = srcTr.property(\"X Rotation\");\n            var yRot = srcTr.property(\"Y Rotation\");\n            var zRot = srcTr.property(\"Z Rotation\");\n\n            if (xRot) dstTr.property(\"X Rotation\").setValue(xRot.value);\n            if (yRot) dstTr.property(\"Y Rotation\").setValue(yRot.value);\n            if (zRot) dstTr.property(\"Z Rotation\").setValue(zRot.value);\n        } catch (e2) {}\n\n        var pos = getLayerPosition(textLayer);\n        setLayerPosition(controller, pos[0], pos[1], pos[2]);\n\n        controller.inPoint = textLayer.inPoint;\n        controller.outPoint = textLayer.outPoint;\n\n        try {\n            controller.moveBefore(textLayer);\n        } catch (e3) {}\n\n        return controller;\n    }\n\n    function makeMeasureLayer(textLayer) {\n        var measureLayer = textLayer.duplicate();\n\n        measureLayer.name = \"TEMP_MEASURE\";\n        measureLayer.enabled = true;\n\n        var textProps = measureLayer.property(\"ADBE Text Properties\");\n        var animators = textProps.property(\"ADBE Text Animators\");\n\n        var animator = animators.addProperty(\"ADBE Text Animator\");\n        animator.name = \"Measurement Isolator\";\n\n        var animatorProps = animator.property(\"ADBE Text Animator Properties\");\n        animatorProps.addProperty(\"ADBE Text Scale 3D\").setValue([0, 0, 100]);\n\n        var selectors = animator.property(\"ADBE Text Selectors\");\n        var rangeSelector = selectors.addProperty(\"ADBE Text Selector\");\n\n        var advancedProps = rangeSelector.property(\"ADBE Text Range Advanced\");\n        advancedProps.property(\"ADBE Text Range Units\").setValue(2);\n        advancedProps.property(\"ADBE Text Range Type2\").setValue(3);\n        advancedProps.property(\"ADBE Text Selector Mode\").setValue(2);\n        advancedProps.property(\"ADBE Text Selector Max Amount\").setValue(100);\n\n        rangeSelector.property(\"ADBE Text Index Start\").setValue(0);\n        rangeSelector.property(\"ADBE Text Index End\").setValue(1);\n\n        return {\n            layer: measureLayer,\n            offset: rangeSelector.property(\"ADBE Text Index Offset\")\n        };\n    }\n\n    function measureWords(textLayer, textContent) {\n        var words = [];\n        var positions = [];\n        var time = textLayer.containingComp.time;\n\n        var regex = /\\S+/g;\n        var match;\n\n        while ((match = regex.exec(textContent)) !== null) {\n            words.push(match[0]);\n        }\n\n        var measure = makeMeasureLayer(textLayer);\n\n        for (var i = 0; i < words.length; i++) {\n            measure.offset.setValue(i);\n\n            var bounds = measure.layer.sourceRectAtTime(time, false);\n\n            positions.push({\n                text: words[i],\n                centerX: bounds.left + bounds.width / 2,\n                centerY: bounds.top + bounds.height / 2\n            });\n        }\n\n        measure.layer.remove();\n\n        return positions;\n    }\n\n    function createWordLayers(textLayer, words) {\n        var comp = textLayer.containingComp;\n        var time = comp.time;\n\n        var controller = createTempController(textLayer);\n        var createdLayers = [];\n\n        for (var i = 0; i < words.length; i++) {\n            var data = words[i];\n\n            if (!data.text) continue;\n\n            try {\n                var newLayer = textLayer.duplicate();\n\n                var textProp = newLayer.property(\"Source Text\");\n                var textDoc = textProp.value;\n                textDoc.text = data.text;\n                textProp.setValue(textDoc);\n\n                newLayer.name = cleanLayerName(data.text, \"Word\");\n\n                var bounds = newLayer.sourceRectAtTime(time, false);\n\n                var anchorX = bounds.left + bounds.width / 2;\n                var anchorY = bounds.top + bounds.height / 2;\n\n                newLayer.property(\"Transform\")\n                    .property(\"Anchor Point\")\n                    .setValue([anchorX, anchorY]);\n\n                newLayer.parent = controller;\n\n                setLayerPosition(newLayer, data.centerX, data.centerY, 0);\n\n                newLayer.opened = false;\n                createdLayers.push(newLayer);\n\n            } catch (err) {}\n        }\n\n        for (var r = createdLayers.length - 1; r >= 0; r--) {\n            try {\n                createdLayers[r].moveBefore(textLayer);\n            } catch (e) {}\n        }\n\n        for (var p = 0; p < createdLayers.length; p++) {\n            try {\n                createdLayers[p].parent = null;\n            } catch (e2) {}\n        }\n\n        try {\n            controller.remove();\n        } catch (e3) {}\n\n        textLayer.enabled = false;\n\n        return createdLayers.length;\n    }\n\n    function splitTextLayerByWords(textLayer) {\n        var textContent = textLayer.property(\"Source Text\").value.text;\n\n        if (!textContent || textContent.length === 0) {\n            return 0;\n        }\n\n        var words = measureWords(textLayer, textContent);\n\n        return createWordLayers(textLayer, words);\n    }\n\n    var comp = app.project.activeItem;\n\n    if (!(comp instanceof CompItem)) {\n        alert(t(\n            \"Veuillez ouvrir une composition.\",\n            \"Please open a composition.\"\n        ));\n        return;\n    }\n\n    var selectedTextLayers = getSelectedTextLayers(comp);\n\n    if (selectedTextLayers.length === 0) {\n        alert(t(\n            \"Veuillez sélectionner un calque texte.\",\n            \"Please select a text layer.\"\n        ));\n        return;\n    }\n\n    app.beginUndoGroup(\"Split Text - Words\");\n\n    for (var i = 0; i < selectedTextLayers.length; i++) {\n        splitTextLayerByWords(selectedTextLayers[i]);\n    }\n\n    app.endUndoGroup();\n\n})();"
            },
            "_imgFile": {
              "filename": "Split-words.svg",
              "encoding": "utf8",
              "content": "<svg width=\"29\" height=\"16\" viewBox=\"0 0 29 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect width=\"21\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"24\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect y=\"6\" width=\"13\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect y=\"12\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect x=\"8\" y=\"12\" width=\"13\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"16\" y=\"6\" width=\"13\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect x=\"24\" y=\"12\" width=\"5\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n</svg>\n"
            }
          },
          {
            "label": "Lines",
            "jsx": "~/Documents/TFS/scripts/Split_Text_Lignes.jsx",
            "type": "script",
            "scriptMode": "file",
            "expressionProperty": "position",
            "expressionCode": "",
            "commandMode": "effect",
            "commandId": "",
            "commandName": "",
            "commandNameFr": "",
            "img": "~/Documents/TFS/img/Split-lines.svg",
            "hideLabel": true,
            "tooltip": "Split Text by Lines",
            "_file": {
              "filename": "Split_Text_Lignes.jsx",
              "encoding": "utf8",
              "content": "(function () {\n\n    var isFrenchAE = (app.isoLanguage && app.isoLanguage.toLowerCase().indexOf(\"fr\") === 0);\n    function t(fr, en) {\n        return isFrenchAE ? fr : en;\n    }\n\n    function isTextLayer(layer) {\n        try {\n            return layer && layer.property(\"ADBE Text Properties\") && layer.property(\"Source Text\");\n        } catch (e) {\n            return false;\n        }\n    }\n\n    function getSelectedTextLayers(comp) {\n        var layers = [];\n\n        for (var i = 0; i < comp.selectedLayers.length; i++) {\n            if (isTextLayer(comp.selectedLayers[i])) {\n                layers.push(comp.selectedLayers[i]);\n            }\n        }\n\n        return layers;\n    }\n\n    function getLayerPosition(layer) {\n        var tr = layer.property(\"Transform\");\n        var p = tr.property(\"Position\");\n\n        if (p.dimensionsSeparated) {\n            var z = 0;\n\n            try {\n                z = tr.property(\"Z Position\").value;\n            } catch (e) {}\n\n            return [\n                tr.property(\"X Position\").value,\n                tr.property(\"Y Position\").value,\n                z\n            ];\n        }\n\n        var v = p.value;\n        return [v[0], v[1], v.length > 2 ? v[2] : 0];\n    }\n\n    function setLayerPosition(layer, x, y, z) {\n        var tr = layer.property(\"Transform\");\n        var p = tr.property(\"Position\");\n\n        if (p.dimensionsSeparated) {\n            tr.property(\"X Position\").setValue(x);\n            tr.property(\"Y Position\").setValue(y);\n\n            try {\n                tr.property(\"Z Position\").setValue(z || 0);\n            } catch (e) {}\n\n        } else {\n            if (p.value.length > 2) {\n                p.setValue([x, y, z || 0]);\n            } else {\n                p.setValue([x, y]);\n            }\n        }\n    }\n\n    function cleanLayerName(txt, fallback) {\n        var name = String(txt)\n            .replace(/\\r\\n|\\r|\\n/g, \" \")\n            .replace(/^\\s+|\\s+$/g, \"\");\n\n        if (!name) name = fallback || \"Line\";\n        if (name.length > 100) name = name.substr(0, 100);\n\n        return name;\n    }\n\n    function createTempController(textLayer) {\n        var comp = textLayer.containingComp;\n        var controller = comp.layers.addNull();\n\n        controller.name = \"TEMP_SPLIT_TEXT_CONTROLLER\";\n\n        var srcTr = textLayer.property(\"Transform\");\n        var dstTr = controller.property(\"Transform\");\n\n        try { dstTr.property(\"Anchor Point\").setValue(srcTr.property(\"Anchor Point\").value); } catch (e) {}\n        try { dstTr.property(\"Scale\").setValue(srcTr.property(\"Scale\").value); } catch (e) {}\n        try { dstTr.property(\"Rotation\").setValue(srcTr.property(\"Rotation\").value); } catch (e) {}\n        try { dstTr.property(\"Opacity\").setValue(srcTr.property(\"Opacity\").value); } catch (e) {}\n\n        try {\n            var xRot = srcTr.property(\"X Rotation\");\n            var yRot = srcTr.property(\"Y Rotation\");\n            var zRot = srcTr.property(\"Z Rotation\");\n\n            if (xRot) dstTr.property(\"X Rotation\").setValue(xRot.value);\n            if (yRot) dstTr.property(\"Y Rotation\").setValue(yRot.value);\n            if (zRot) dstTr.property(\"Z Rotation\").setValue(zRot.value);\n        } catch (e2) {}\n\n        var pos = getLayerPosition(textLayer);\n        setLayerPosition(controller, pos[0], pos[1], pos[2]);\n\n        controller.inPoint = textLayer.inPoint;\n        controller.outPoint = textLayer.outPoint;\n\n        try {\n            controller.moveBefore(textLayer);\n        } catch (e3) {}\n\n        return controller;\n    }\n\n    function makeMeasureLayer(textLayer) {\n        var measureLayer = textLayer.duplicate();\n\n        measureLayer.name = \"TEMP_MEASURE\";\n        measureLayer.enabled = true;\n\n        var textProps = measureLayer.property(\"ADBE Text Properties\");\n        var animators = textProps.property(\"ADBE Text Animators\");\n\n        var animator = animators.addProperty(\"ADBE Text Animator\");\n        animator.name = \"Measurement Isolator\";\n\n        var animatorProps = animator.property(\"ADBE Text Animator Properties\");\n        animatorProps.addProperty(\"ADBE Text Scale 3D\").setValue([0, 0, 100]);\n\n        var selectors = animator.property(\"ADBE Text Selectors\");\n        var rangeSelector = selectors.addProperty(\"ADBE Text Selector\");\n\n        var advancedProps = rangeSelector.property(\"ADBE Text Range Advanced\");\n        advancedProps.property(\"ADBE Text Range Units\").setValue(2);\n        advancedProps.property(\"ADBE Text Range Type2\").setValue(4);\n        advancedProps.property(\"ADBE Text Selector Mode\").setValue(2);\n        advancedProps.property(\"ADBE Text Selector Max Amount\").setValue(100);\n\n        rangeSelector.property(\"ADBE Text Index Start\").setValue(0);\n        rangeSelector.property(\"ADBE Text Index End\").setValue(1);\n\n        return {\n            layer: measureLayer,\n            offset: rangeSelector.property(\"ADBE Text Index Offset\")\n        };\n    }\n\n    function measureLines(textLayer, textContent) {\n        var lines = [];\n        var positions = [];\n        var time = textLayer.containingComp.time;\n\n        var allLines = textContent.split(/\\r\\n|\\r|\\n/);\n\n        for (var i = 0; i < allLines.length; i++) {\n            if (allLines[i].length > 0) {\n                lines.push(allLines[i]);\n            }\n        }\n\n        var measure = makeMeasureLayer(textLayer);\n\n        for (var l = 0; l < lines.length; l++) {\n            measure.offset.setValue(l);\n\n            var bounds = measure.layer.sourceRectAtTime(time, false);\n\n            positions.push({\n                text: lines[l],\n                centerX: bounds.left + bounds.width / 2,\n                centerY: bounds.top + bounds.height / 2\n            });\n        }\n\n        measure.layer.remove();\n\n        return positions;\n    }\n\n    function createLineLayers(textLayer, lines) {\n        var comp = textLayer.containingComp;\n        var time = comp.time;\n\n        var controller = createTempController(textLayer);\n        var createdLayers = [];\n\n        for (var i = 0; i < lines.length; i++) {\n            var data = lines[i];\n\n            if (!data.text) continue;\n\n            try {\n                var newLayer = textLayer.duplicate();\n\n                var textProp = newLayer.property(\"Source Text\");\n                var textDoc = textProp.value;\n                textDoc.text = data.text;\n                textProp.setValue(textDoc);\n\n                newLayer.name = cleanLayerName(data.text, \"Line\");\n\n                var bounds = newLayer.sourceRectAtTime(time, false);\n\n                var anchorX = bounds.left + bounds.width / 2;\n                var anchorY = bounds.top + bounds.height / 2;\n\n                newLayer.property(\"Transform\")\n                    .property(\"Anchor Point\")\n                    .setValue([anchorX, anchorY]);\n\n                newLayer.parent = controller;\n\n                setLayerPosition(newLayer, data.centerX, data.centerY, 0);\n\n                newLayer.opened = false;\n                createdLayers.push(newLayer);\n\n            } catch (err) {}\n        }\n\n        for (var r = createdLayers.length - 1; r >= 0; r--) {\n            try {\n                createdLayers[r].moveBefore(textLayer);\n            } catch (e) {}\n        }\n\n        for (var p = 0; p < createdLayers.length; p++) {\n            try {\n                createdLayers[p].parent = null;\n            } catch (e2) {}\n        }\n\n        try {\n            controller.remove();\n        } catch (e3) {}\n\n        textLayer.enabled = false;\n\n        return createdLayers.length;\n    }\n\n    function splitTextLayerByLines(textLayer) {\n        var textContent = textLayer.property(\"Source Text\").value.text;\n\n        if (!textContent || textContent.length === 0) {\n            return 0;\n        }\n\n        var lines = measureLines(textLayer, textContent);\n\n        return createLineLayers(textLayer, lines);\n    }\n\n    var comp = app.project.activeItem;\n\n    if (!(comp instanceof CompItem)) {\n        alert(t(\n            \"Veuillez ouvrir une composition.\",\n            \"Please open a composition.\"\n        ));\n        return;\n    }\n\n    var selectedTextLayers = getSelectedTextLayers(comp);\n\n    if (selectedTextLayers.length === 0) {\n        alert(t(\n            \"Veuillez sélectionner un calque texte.\",\n            \"Please select a text layer.\"\n        ));\n        return;\n    }\n\n    app.beginUndoGroup(\"Split Text - Lines\");\n\n    for (var i = 0; i < selectedTextLayers.length; i++) {\n        splitTextLayerByLines(selectedTextLayers[i]);\n    }\n\n    app.endUndoGroup();\n\n})();"
            },
            "_imgFile": {
              "filename": "Split-lines.svg",
              "encoding": "utf8",
              "content": "<svg width=\"29\" height=\"16\" viewBox=\"0 0 29 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect width=\"18\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n<rect y=\"6\" width=\"29\" height=\"4\" rx=\"1\" fill=\"#00A0FF\" fill-opacity=\"0.3\"/>\n<rect y=\"12\" width=\"24\" height=\"4\" rx=\"1\" fill=\"#00A0FF\"/>\n</svg>\n"
            }
          }
        ]
      }
    ]
  }
}